diff options
43 files changed, 1362 insertions, 599 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp index 4e1de0ecf9d4..fe84a7ac7715 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -139,12 +139,6 @@ droidstubs { baseline_file: "api/lint-baseline.txt", }, }, - dist: { - targets: ["sdk", "win_sdk"], - dir: "apistubs/android/public/api", - dest: "android.txt", - }, - jdiff_enabled: true, } droidstubs { @@ -206,12 +200,6 @@ droidstubs { baseline_file: "api/system-lint-baseline.txt", }, }, - dist: { - targets: ["sdk", "win_sdk"], - dir: "apistubs/android/system/api", - dest: "android.txt", - }, - jdiff_enabled: true, } droidstubs { @@ -291,11 +279,6 @@ droidstubs { baseline_file: "api/module-lib-lint-baseline.txt", }, }, - dist: { - targets: ["sdk", "win_sdk"], - dir: "apistubs/android/module-lib/api", - dest: "android.txt", - }, } droidstubs { diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl index 5cdb3249501b..d56a4bd0a8e5 100644 --- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl +++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl @@ -27,17 +27,6 @@ interface IStatsCompanionService { oneway void statsdReady(); /** - * Register an alarm for anomaly detection to fire at the given timestamp (ms since epoch). - * If anomaly alarm had already been registered, it will be replaced with the new timestamp. - * Uses AlarmManager.set API, so if the timestamp is in the past, alarm fires immediately, and - * alarm is inexact. - */ - oneway void setAnomalyAlarm(long timestampMs); - - /** Cancel any anomaly detection alarm. */ - oneway void cancelAnomalyAlarm(); - - /** * Register a repeating alarm for pulling to fire at the given timestamp and every * intervalMs thereafter (in ms since epoch). * If polling alarm had already been registered, it will be replaced by new one. diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl index 0d3f4208a2ab..066412a9f157 100644 --- a/apex/statsd/aidl/android/os/IStatsd.aidl +++ b/apex/statsd/aidl/android/os/IStatsd.aidl @@ -42,13 +42,6 @@ interface IStatsd { void statsCompanionReady(); /** - * Tells statsd that an anomaly may have occurred, so statsd can check whether this is so and - * act accordingly. - * Two-way binder call so that caller's method (and corresponding wakelocks) will linger. - */ - void informAnomalyAlarmFired(); - - /** * Tells statsd that it is time to poll some stats. Statsd will be responsible for determing * what stats to poll and initiating the polling. * Two-way binder call so that caller's method (and corresponding wakelocks) will linger. diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index cbc8ed636ff2..b5e72247a4a3 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -100,7 +100,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private static IStatsd sStatsd; private static final Object sStatsdLock = new Object(); - private final OnAlarmListener mAnomalyAlarmListener; private final OnAlarmListener mPullingAlarmListener; private final OnAlarmListener mPeriodicAlarmListener; @@ -124,7 +123,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { handlerThread.start(); mHandler = new CompanionHandler(handlerThread.getLooper()); - mAnomalyAlarmListener = new AnomalyAlarmListener(context); mPullingAlarmListener = new PullingAlarmListener(context); mPeriodicAlarmListener = new PeriodicAlarmListener(context); } @@ -336,41 +334,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - public static final class AnomalyAlarmListener implements OnAlarmListener { - private final Context mContext; - - AnomalyAlarmListener(Context context) { - mContext = context; - } - - @Override - public void onAlarm() { - if (DEBUG) { - Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time " - + System.currentTimeMillis() + "ms."); - } - IStatsd statsd = getStatsdNonblocking(); - if (statsd == null) { - Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing"); - return; - } - - // Wakelock needs to be retained while calling statsd. - Thread thread = new WakelockThread(mContext, - AnomalyAlarmListener.class.getCanonicalName(), new Runnable() { - @Override - public void run() { - try { - statsd.informAnomalyAlarmFired(); - } catch (RemoteException e) { - Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e); - } - } - }); - thread.start(); - } - } - public final static class PullingAlarmListener implements OnAlarmListener { private final Context mContext; @@ -469,34 +432,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } @Override // Binder call - public void setAnomalyAlarm(long timestampMs) { - StatsCompanion.enforceStatsdCallingUid(); - if (DEBUG) Log.d(TAG, "Setting anomaly alarm for " + timestampMs); - final long callingToken = Binder.clearCallingIdentity(); - try { - // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will - // only fire when it awakens. - // AlarmManager will automatically cancel any previous mAnomalyAlarmListener alarm. - mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".anomaly", - mAnomalyAlarmListener, mHandler); - } finally { - Binder.restoreCallingIdentity(callingToken); - } - } - - @Override // Binder call - public void cancelAnomalyAlarm() { - StatsCompanion.enforceStatsdCallingUid(); - if (DEBUG) Log.d(TAG, "Cancelling anomaly alarm"); - final long callingToken = Binder.clearCallingIdentity(); - try { - mAlarmManager.cancel(mAnomalyAlarmListener); - } finally { - Binder.restoreCallingIdentity(callingToken); - } - } - - @Override // Binder call public void setAlarmForSubscriberTriggering(long timestampMs) { StatsCompanion.enforceStatsdCallingUid(); if (DEBUG) { @@ -666,7 +601,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { // instead of in binder death because statsd can come back and set different alarms, or not // want to set an alarm when it had been set. This guarantees that when we get a new statsd, // we cancel any alarms before it is able to set them. - cancelAnomalyAlarm(); cancelPullingAlarm(); cancelAlarmForSubscriberTriggering(); diff --git a/api/Android.bp b/api/Android.bp index ffc4a2146594..fd0303b31de9 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -60,6 +60,11 @@ genrule { out: ["current.txt"], tools: ["metalava"], cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dist: { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/public/api", + dest: "android.txt", + }, } genrule { @@ -95,6 +100,11 @@ genrule { out: ["system-current.txt"], tools: ["metalava"], cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dist: { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system/api", + dest: "android.txt", + }, } genrule { @@ -129,6 +139,11 @@ genrule { out: ["module-lib-current.txt"], tools: ["metalava"], cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dist: { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/module-lib/api", + dest: "android.txt", + }, } genrule { diff --git a/api/current.txt b/api/current.txt index d9239724210f..be3c35c0ff79 100644 --- a/api/current.txt +++ b/api/current.txt @@ -48279,7 +48279,7 @@ package android.telephony { method @Deprecated public int getPhoneCount(); method public int getPhoneType(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription(); - method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState(); + method @Nullable @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState(); method @Nullable public android.telephony.SignalStrength getSignalStrength(); method public int getSimCarrierId(); method @Nullable public CharSequence getSimCarrierIdName(); @@ -48302,7 +48302,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType(); - method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); + method @Nullable public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); method public boolean hasCarrierPrivileges(); method public boolean hasIccCard(); method @Deprecated public boolean iccCloseLogicalChannel(int); diff --git a/api/test-current.txt b/api/test-current.txt index 2cb106e7fd51..3bf0f03c77f5 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -19,6 +19,7 @@ package android { field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK"; field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS"; field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS"; + field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE"; field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS"; field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS"; @@ -3387,7 +3388,7 @@ package android.security { package android.security.keystore { public abstract class AttestationUtils { - method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException; + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static java.security.cert.X509Certificate[] attestDeviceIds(android.content.Context, @NonNull int[], @NonNull byte[]) throws android.security.keystore.DeviceIdAttestationException; field public static final int ID_TYPE_IMEI = 2; // 0x2 field public static final int ID_TYPE_MEID = 3; // 0x3 field public static final int ID_TYPE_SERIAL = 1; // 0x1 @@ -3923,11 +3924,11 @@ package android.telecom { public class TelecomManager { method @NonNull public android.content.Intent createLaunchEmergencyDialerIntent(@Nullable String); - method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode(); - method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDefaultDialerPackage(@NonNull android.os.UserHandle); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode(); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(@NonNull android.os.UserHandle); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall(); - method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle); field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED"; field public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED"; @@ -4113,7 +4114,7 @@ package android.telephony { method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public android.content.ComponentName getDefaultRespondViaMessageApplication(); method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getEmergencyNumberDbVersion(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting); @@ -4351,14 +4352,14 @@ package android.telephony.ims { } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { - method @Deprecated @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiRoamingModeSetting(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAvailable(int, int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isCapable(int, int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void isSupported(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; - method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; + method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(int, int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(int, int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int); @@ -4367,7 +4368,7 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean); - method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback); + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback); } @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback { @@ -4600,17 +4601,17 @@ package android.telephony.ims { public class ProvisioningManager { method @NonNull public static android.telephony.ims.ProvisioningManager createForSubscriptionId(int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public int getProvisioningIntValue(int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getProvisioningStatusForCapability(int, int); - method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public String getProvisioningStringValue(int); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public int getProvisioningIntValue(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(int, int); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); field public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; // 0x43 field public static final int KEY_VOICE_OVER_WIFI_MODE_OVERRIDE = 27; // 0x1b field public static final int KEY_VOICE_OVER_WIFI_ROAMING_ENABLED_OVERRIDE = 26; // 0x1a diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index e7b32c56551a..c10f248f4702 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -120,10 +120,9 @@ static void flushProtoToBuffer(ProtoOutputStream& proto, vector<uint8_t>* outDat } } -void StatsLogProcessor::onAnomalyAlarmFired( +void StatsLogProcessor::processFiredAnomalyAlarmsLocked( const int64_t& timestampNs, unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) { - std::lock_guard<std::mutex> lock(mMetricsMutex); for (const auto& itr : mMetricsManagers) { itr.second->onAnomalyAlarmFired(timestampNs, alarmSet); } @@ -431,6 +430,20 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) { return; } + bool fireAlarm = false; + { + std::lock_guard<std::mutex> anomalyLock(mAnomalyAlarmMutex); + if (mNextAnomalyAlarmTime != 0 && + MillisToNano(mNextAnomalyAlarmTime) <= elapsedRealtimeNs) { + mNextAnomalyAlarmTime = 0; + VLOG("informing anomaly alarm at time %lld", (long long)elapsedRealtimeNs); + fireAlarm = true; + } + } + if (fireAlarm) { + informAnomalyAlarmFiredLocked(NanoToMillis(elapsedRealtimeNs)); + } + int64_t curTimeSec = getElapsedRealtimeSec(); if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) { mPullerManager->ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC); @@ -1092,6 +1105,28 @@ void StatsLogProcessor::noteOnDiskData(const ConfigKey& key) { mOnDiskDataConfigs.insert(key); } +void StatsLogProcessor::setAnomalyAlarm(const int64_t elapsedTimeMillis) { + std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex); + mNextAnomalyAlarmTime = elapsedTimeMillis; +} + +void StatsLogProcessor::cancelAnomalyAlarm() { + std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex); + mNextAnomalyAlarmTime = 0; +} + +void StatsLogProcessor::informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis) { + VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called"); + std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet = + mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(elapsedTimeMillis / 1000)); + if (alarmSet.size() > 0) { + VLOG("Found periodic alarm fired."); + processFiredAnomalyAlarmsLocked(MillisToNano(elapsedTimeMillis), alarmSet); + } else { + ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled."); + } +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 23f2584655b0..08f46688bbba 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -66,11 +66,6 @@ public: const DumpLatency dumpLatency, ProtoOutputStream* proto); - /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */ - void onAnomalyAlarmFired( - const int64_t& timestampNs, - unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet); - /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */ void onPeriodicAlarmFired( const int64_t& timestampNs, @@ -148,6 +143,10 @@ public: // Add a specific config key to the possible configs to dump ASAP. void noteOnDiskData(const ConfigKey& key); + void setAnomalyAlarm(const int64_t timeMillis); + + void cancelAnomalyAlarm(); + private: // For testing only. inline sp<AlarmMonitor> getAnomalyAlarmMonitor() const { @@ -160,6 +159,11 @@ private: mutable mutex mMetricsMutex; + // Guards mNextAnomalyAlarmTime. A separate mutex is needed because alarms are set/cancelled + // in the onLogEvent code path, which is locked by mMetricsMutex. + // DO NOT acquire mMetricsMutex while holding mAnomalyAlarmMutex. This can lead to a deadlock. + mutable mutex mAnomalyAlarmMutex; + std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers; std::unordered_map<ConfigKey, int64_t> mLastBroadcastTimes; @@ -250,6 +254,15 @@ private: // Reset the specified configs. void resetConfigsLocked(const int64_t timestampNs, const std::vector<ConfigKey>& configs); + // An anomaly alarm should have fired. + // Check with anomaly alarm manager to find the alarms and process the result. + void informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis); + + /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */ + void processFiredAnomalyAlarmsLocked( + const int64_t& timestampNs, + unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet); + // Function used to send a broadcast so that receiver for the config key can call getData // to retrieve the stored data. std::function<bool(const ConfigKey& key)> mSendBroadcast; @@ -276,6 +289,9 @@ private: //Last time we wrote metadata to disk. int64_t mLastMetadataWriteNs = 0; + // The time for the next anomaly alarm for alerts. + int64_t mNextAnomalyAlarmTime = 0; + #ifdef VERY_VERBOSE_PRINTING bool mPrintAllLogs = false; #endif diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 322648229d0e..368a6c40c746 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -91,17 +91,13 @@ Status checkUid(uid_t expectedUid) { StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue) : mAnomalyAlarmMonitor(new AlarmMonitor( MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS, - [](const shared_ptr<IStatsCompanionService>& sc, int64_t timeMillis) { - if (sc != nullptr) { - sc->setAnomalyAlarm(timeMillis); - StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); - } + [this](const shared_ptr<IStatsCompanionService>& /*sc*/, int64_t timeMillis) { + mProcessor->setAnomalyAlarm(timeMillis); + StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); }, - [](const shared_ptr<IStatsCompanionService>& sc) { - if (sc != nullptr) { - sc->cancelAnomalyAlarm(); - StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); - } + [this](const shared_ptr<IStatsCompanionService>& /*sc*/) { + mProcessor->cancelAnomalyAlarm(); + StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); })), mPeriodicAlarmMonitor(new AlarmMonitor( MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS, @@ -975,22 +971,6 @@ Status StatsService::informOnePackageRemoved(const string& app, int32_t uid) { return Status::ok(); } -Status StatsService::informAnomalyAlarmFired() { - ENFORCE_UID(AID_SYSTEM); - - VLOG("StatsService::informAnomalyAlarmFired was called"); - int64_t currentTimeSec = getElapsedRealtimeSec(); - std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet = - mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec)); - if (alarmSet.size() > 0) { - VLOG("Found an anomaly alarm that fired."); - mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet); - } else { - VLOG("Cannot find an anomaly alarm that fired. Perhaps it was recently cancelled."); - } - return Status::ok(); -} - Status StatsService::informAlarmForSubscriberTriggeringFired() { ENFORCE_UID(AID_SYSTEM); diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 324ffbd65e51..479f4e87ec96 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -66,7 +66,6 @@ public: virtual Status systemRunning(); virtual Status statsCompanionReady(); virtual Status bootCompleted(); - virtual Status informAnomalyAlarmFired(); virtual Status informPollAlarmFired(); virtual Status informAlarmForSubscriberTriggeringFired(); @@ -404,6 +403,10 @@ private: FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricOnBootWithoutMinPartialBucket); FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket); FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket); + + FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket); + FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets); + FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period); }; } // namespace statsd diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp index 95e301002a1b..70e7365ec238 100644 --- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp @@ -12,14 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include <android/binder_ibinder.h> +#include <android/binder_interface_utils.h> #include <gtest/gtest.h> -#include "src/anomaly/DurationAnomalyTracker.h" +#include <vector> + #include "src/StatsLogProcessor.h" +#include "src/StatsService.h" +#include "src/anomaly/DurationAnomalyTracker.h" #include "src/stats_log_util.h" #include "tests/statsd_test_util.h" -#include <vector> +using ::ndk::SharedRefBase; namespace android { namespace os { @@ -29,6 +34,9 @@ namespace statsd { namespace { +const int kConfigKey = 789130124; +const int kCallingUid = 0; + StatsdConfig CreateStatsdConfig(int num_buckets, uint64_t threshold_ns, DurationMetric::AggregationType aggregationType, @@ -89,6 +97,13 @@ MetricDimensionKey dimensionKey2( (int32_t)0x02010101), Value((int32_t)222))}), DEFAULT_DIMENSION_KEY); +void sendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) { + string str; + config.SerializeToString(&str); + std::vector<uint8_t> configAsVec(str.begin(), str.end()); + service->addConfiguration(kConfigKey, configAsVec, kCallingUid); +} + } // namespace TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { @@ -98,16 +113,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { const uint64_t alert_id = config.alert(0).id(); const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); - int64_t bucketStartTimeNs = 10 * NS_PER_SEC; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + sendConfig(service, config); - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + auto processor = service->mProcessor; ASSERT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + int64_t bucketStartTimeNs = processor->mTimeBaseNs; + int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6; + sp<AnomalyTracker> anomalyTracker = processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; @@ -158,12 +175,13 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1); EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1, (uint32_t)alarmFiredTimestampSec0); + EXPECT_EQ(alarmFiredTimestampSec0, + processor->getAnomalyAlarmMonitor()->getRegisteredAlarmTimeSec()); // Anomaly alarm fired. - auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( - static_cast<uint32_t>(alarmFiredTimestampSec0)); - ASSERT_EQ(1u, alarmSet.size()); - processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet); + auto alarmTriggerEvent = CreateBatterySaverOnEvent(alarmFiredTimestampSec0 * NS_PER_SEC); + processor->OnLogEvent(alarmTriggerEvent.get(), alarmFiredTimestampSec0 * NS_PER_SEC); + EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); @@ -179,39 +197,39 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire wakelock wl1. - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, - attributionUids2, attributionTags2, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, attributionUids2, + attributionTags2, "wl1"); processor->OnLogEvent(acquire_event.get()); const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1); EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC, (uint64_t)alarmFiredTimestampSec1); // Release wakelock wl1. - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10, - attributionUids2, attributionTags2, "wl1"); - processor->OnLogEvent(release_event.get()); + int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - EXPECT_EQ(refractory_period_sec + - (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( + auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( static_cast<uint32_t>(alarmFiredTimestampSec1)); ASSERT_EQ(0u, alarmSet.size()); // Acquire wakelock wl1 near the end of bucket #0. - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2, + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 2, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Release the event at early bucket #1. - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Anomaly detected when stopping the alarm. The refractory period does not change. EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC, @@ -236,17 +254,17 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { // Condition turns true. screen_off_event = - CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC, + CreateScreenStateChangedEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC, android::view::DisplayStateEnum::DISPLAY_STATE_OFF); processor->OnLogEvent(screen_off_event.get()); EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Condition turns to false. - screen_on_event = - CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1, - android::view::DisplayStateEnum::DISPLAY_STATE_ON); - processor->OnLogEvent(screen_on_event.get()); + int64_t condition_false_time = bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1; + screen_on_event = CreateScreenStateChangedEvent( + condition_false_time, android::view::DisplayStateEnum::DISPLAY_STATE_ON); + processor->OnLogEvent(screen_on_event.get(), condition_false_time); // Condition turns to false. Cancelled the alarm. EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Detected one anomaly. @@ -262,12 +280,11 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) { EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC, - attributionUids2, attributionTags2, "wl1"); + release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); processor->OnLogEvent(release_event.get()); - EXPECT_EQ(refractory_period_sec + - (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); } @@ -279,16 +296,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) { const uint64_t alert_id = config.alert(0).id(); const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs(); - int64_t bucketStartTimeNs = 10 * NS_PER_SEC; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + sendConfig(service, config); - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + auto processor = service->mProcessor; ASSERT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + int64_t bucketStartTimeNs = processor->mTimeBaseNs; + int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC; + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6; + sp<AnomalyTracker> anomalyTracker = processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; @@ -298,96 +317,97 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) { // Acquire wakelock "wc1" in bucket #0. auto acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1, + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Release wakelock "wc1" in bucket #0. - auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 1; + auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire wakelock "wc1" in bucket #1. - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, - attributionUids2, attributionTags2, "wl1"); + acquire_event = + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 1, + attributionUids2, attributionTags2, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100, - attributionUids2, attributionTags2, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 100; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire wakelock "wc2" in bucket #2. - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, - attributionUids3, attributionTags3, "wl2"); + acquire_event = + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + 1, + attributionUids3, attributionTags3, "wl2"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2, + EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); // Release wakelock "wc2" in bucket #2. - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC, - attributionUids3, attributionTags3, "wl2"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3, + attributionTags3, "wl2"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); - EXPECT_EQ(refractory_period_sec + - (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2)); // Acquire wakelock "wc1" in bucket #2. acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC, + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, attributionUids2, attributionTags2, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1, + EXPECT_EQ((roundedBucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3 + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Release wakelock "wc1" in bucket #2. - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC, - attributionUids2, attributionTags2, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3.5 * NS_PER_SEC; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2, + attributionTags2, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - EXPECT_EQ(refractory_period_sec + - (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / - NS_PER_SEC + - 1, + EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4, - attributionUids3, attributionTags3, "wl2"); + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 4, + attributionUids3, attributionTags3, "wl2"); processor->OnLogEvent(acquire_event.get()); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 5, + attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1, + EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2, - attributionUids3, attributionTags3, "wl2"); - processor->OnLogEvent(release_event.get()); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC + 2; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3, + attributionTags3, "wl2"); + processor->OnLogEvent(release_event.get(), release_event_time); + release_event = CreateReleaseWakelockEvent(release_event_time + 4, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time + 4); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2)); // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered. - EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + + EXPECT_EQ(refractory_period_sec + + (int64_t)(roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC) / + NS_PER_SEC + 1, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); } @@ -396,20 +416,22 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) { const int num_buckets = 2; const uint64_t threshold_ns = 3 * NS_PER_SEC; auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false); - int64_t bucketStartTimeNs = 10 * NS_PER_SEC; - int64_t bucketSizeNs = - TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000; - const uint64_t alert_id = config.alert(0).id(); + int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6; const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC; config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec); - ConfigKey cfgKey; - auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey); + shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr); + sendConfig(service, config); + + auto processor = service->mProcessor; ASSERT_EQ(processor->mMetricsManagers.size(), 1u); EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid()); ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size()); + int64_t bucketStartTimeNs = processor->mTimeBaseNs; + int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC; + sp<AnomalyTracker> anomalyTracker = processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0]; @@ -418,81 +440,81 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) { processor->OnLogEvent(screen_off_event.get()); // Acquire wakelock "wc1" in bucket #0. - auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100, + auto acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 100, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, + EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Acquire the wakelock "wc1" again. acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1, + CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); // The alarm does not change. - EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, + EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // Anomaly alarm fired late. - const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC; - auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan( - static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC)); - ASSERT_EQ(1u, alarmSet.size()); - processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet); + const int64_t firedAlarmTimestampNs = roundedBucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC; + auto alarmTriggerEvent = CreateBatterySaverOnEvent(firedAlarmTimestampNs); + processor->OnLogEvent(alarmTriggerEvent.get(), firedAlarmTimestampNs); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100, + acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs - 100, attributionUids1, attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + int64_t release_event_time = bucketStartTimeNs + 2 * bucketSizeNs + 1; + auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); // Within the refractory period. No anomaly. EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); // A new wakelock, but still within refractory period. - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, attributionUids1, + attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC, - attributionUids1, attributionTags1, "wl1"); + release_event = + CreateReleaseWakelockEvent(roundedBucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC, + attributionUids1, attributionTags1, "wl1"); // Still in the refractory period. No anomaly. processor->OnLogEvent(release_event.get()); EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1)); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 5, attributionUids1, + attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, + EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - release_event = - CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4, - attributionUids1, attributionTags1, "wl1"); - processor->OnLogEvent(release_event.get()); + release_event_time = roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 4; + release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1, + attributionTags1, "wl1"); + processor->OnLogEvent(release_event.get(), release_event_time); EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); - acquire_event = - CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3, - attributionUids1, attributionTags1, "wl1"); + acquire_event = CreateAcquireWakelockEvent( + roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 3, attributionUids1, + attributionTags1, "wl1"); processor->OnLogEvent(acquire_event.get()); - EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC, + EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1, anomalyTracker->getAlarmTimestampSec(dimensionKey1)); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 1fce990e01c0..237175d42dd1 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -5718,8 +5718,8 @@ public class DevicePolicyManager { * System apps can always bypass VPN. * <p> Note that the system doesn't update the allowlist when packages are installed or * uninstalled, the admin app must call this method to keep the list up to date. - * <p> When {@code lockdownEnabled} is false {@code lockdownWhitelist} is ignored . When - * {@code lockdownEnabled} is {@code true} and {@code lockdownWhitelist} is {@code null} or + * <p> When {@code lockdownEnabled} is false {@code lockdownAllowlist} is ignored . When + * {@code lockdownEnabled} is {@code true} and {@code lockdownAllowlist} is {@code null} or * empty, only system apps can bypass VPN. * <p> Setting always-on VPN package to {@code null} or using * {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} clears lockdown allowlist. @@ -5728,24 +5728,24 @@ public class DevicePolicyManager { * to remove an existing always-on VPN configuration * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or * {@code false} otherwise. This has no effect when clearing. - * @param lockdownWhitelist Packages that will be able to access the network directly when VPN + * @param lockdownAllowlist Packages that will be able to access the network directly when VPN * is in lockdown mode but not connected. Has no effect when clearing. * @throws SecurityException if {@code admin} is not a device or a profile * owner. * @throws NameNotFoundException if {@code vpnPackage} or one of - * {@code lockdownWhitelist} is not installed. + * {@code lockdownAllowlist} is not installed. * @throws UnsupportedOperationException if {@code vpnPackage} exists but does * not support being set as always-on, or if always-on VPN is not * available. */ public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage, - boolean lockdownEnabled, @Nullable Set<String> lockdownWhitelist) + boolean lockdownEnabled, @Nullable Set<String> lockdownAllowlist) throws NameNotFoundException { throwIfParentInstance("setAlwaysOnVpnPackage"); if (mService != null) { try { mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, - lockdownWhitelist == null ? null : new ArrayList<>(lockdownWhitelist)); + lockdownAllowlist == null ? null : new ArrayList<>(lockdownAllowlist)); } catch (ServiceSpecificException e) { switch (e.errorCode) { case ERROR_VPN_PACKAGE_NOT_FOUND: @@ -5820,9 +5820,9 @@ public class DevicePolicyManager { throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist"); if (mService != null) { try { - final List<String> whitelist = - mService.getAlwaysOnVpnLockdownWhitelist(admin); - return whitelist == null ? null : new HashSet<>(whitelist); + final List<String> allowlist = + mService.getAlwaysOnVpnLockdownAllowlist(admin); + return allowlist == null ? null : new HashSet<>(allowlist); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/admin/FreezePeriod.java b/core/java/android/app/admin/FreezePeriod.java index 657f0177097e..eb6efec1c330 100644 --- a/core/java/android/app/admin/FreezePeriod.java +++ b/core/java/android/app/admin/FreezePeriod.java @@ -39,8 +39,8 @@ import java.util.List; public class FreezePeriod { private static final String TAG = "FreezePeriod"; - private static final int DUMMY_YEAR = 2001; - static final int DAYS_IN_YEAR = 365; // 365 since DUMMY_YEAR is not a leap year + private static final int SENTINEL_YEAR = 2001; + static final int DAYS_IN_YEAR = 365; // 365 since SENTINEL_YEAR is not a leap year private final MonthDay mStart; private final MonthDay mEnd; @@ -60,9 +60,9 @@ public class FreezePeriod { */ public FreezePeriod(MonthDay start, MonthDay end) { mStart = start; - mStartDay = mStart.atYear(DUMMY_YEAR).getDayOfYear(); + mStartDay = mStart.atYear(SENTINEL_YEAR).getDayOfYear(); mEnd = end; - mEndDay = mEnd.atYear(DUMMY_YEAR).getDayOfYear(); + mEndDay = mEnd.atYear(SENTINEL_YEAR).getDayOfYear(); } /** @@ -166,9 +166,9 @@ public class FreezePeriod { endYearAdjustment = 1; } } - final LocalDate startDate = LocalDate.ofYearDay(DUMMY_YEAR, mStartDay).withYear( + final LocalDate startDate = LocalDate.ofYearDay(SENTINEL_YEAR, mStartDay).withYear( now.getYear() + startYearAdjustment); - final LocalDate endDate = LocalDate.ofYearDay(DUMMY_YEAR, mEndDay).withYear( + final LocalDate endDate = LocalDate.ofYearDay(SENTINEL_YEAR, mEndDay).withYear( now.getYear() + endYearAdjustment); return new Pair<>(startDate, endDate); } @@ -176,13 +176,13 @@ public class FreezePeriod { @Override public String toString() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd"); - return LocalDate.ofYearDay(DUMMY_YEAR, mStartDay).format(formatter) + " - " - + LocalDate.ofYearDay(DUMMY_YEAR, mEndDay).format(formatter); + return LocalDate.ofYearDay(SENTINEL_YEAR, mStartDay).format(formatter) + " - " + + LocalDate.ofYearDay(SENTINEL_YEAR, mEndDay).format(formatter); } /** @hide */ private static MonthDay dayOfYearToMonthDay(int dayOfYear) { - LocalDate date = LocalDate.ofYearDay(DUMMY_YEAR, dayOfYear); + LocalDate date = LocalDate.ofYearDay(SENTINEL_YEAR, dayOfYear); return MonthDay.of(date.getMonth(), date.getDayOfMonth()); } @@ -191,7 +191,7 @@ public class FreezePeriod { * @hide */ private static int dayOfYearDisregardLeapYear(LocalDate date) { - return date.withYear(DUMMY_YEAR).getDayOfYear(); + return date.withYear(SENTINEL_YEAR).getDayOfYear(); } /** diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 9c6a274ccf8c..3ad8b4b5294f 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -197,12 +197,12 @@ interface IDevicePolicyManager { void setCertInstallerPackage(in ComponentName who, String installerPackage); String getCertInstallerPackage(in ComponentName who); - boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownWhitelist); + boolean setAlwaysOnVpnPackage(in ComponentName who, String vpnPackage, boolean lockdown, in List<String> lockdownAllowlist); String getAlwaysOnVpnPackage(in ComponentName who); String getAlwaysOnVpnPackageForUser(int userHandle); boolean isAlwaysOnVpnLockdownEnabled(in ComponentName who); boolean isAlwaysOnVpnLockdownEnabledForUser(int userHandle); - List<String> getAlwaysOnVpnLockdownWhitelist(in ComponentName who); + List<String> getAlwaysOnVpnLockdownAllowlist(in ComponentName who); void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 4b661ca3ab80..236e67a1ea70 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -951,7 +951,7 @@ public class ChooserActivity extends ResolverActivity implements updateStickyContentPreview(); if (shouldShowStickyContentPreview() || mChooserMultiProfilePagerAdapter - .getCurrentRootAdapter().getContentPreviewRowCount() != 0) { + .getCurrentRootAdapter().getSystemRowCount() != 0) { logActionShareWithPreview(); } return postRebuildListInternal(rebuildCompleted); @@ -1316,13 +1316,14 @@ public class ChooserActivity extends ResolverActivity implements ViewGroup parent) { ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_image, parent, false); + ViewGroup imagePreview = contentPreviewLayout.findViewById(R.id.content_preview_image_area); final ViewGroup actionRow = (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row); //TODO: addActionButton(actionRow, createCopyButton()); addActionButton(actionRow, createNearbyButton(targetIntent)); - mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, true); + mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, false); String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { @@ -1342,7 +1343,7 @@ public class ChooserActivity extends ResolverActivity implements if (imageUris.size() == 0) { Log.i(TAG, "Attempted to display image preview area with zero" + " available images detected in EXTRA_STREAM list"); - contentPreviewLayout.setVisibility(View.GONE); + imagePreview.setVisibility(View.GONE); return contentPreviewLayout; } @@ -2680,7 +2681,7 @@ public class ChooserActivity extends ResolverActivity implements final int bottomInset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0; int offset = bottomInset; - int rowsToShow = gridAdapter.getContentPreviewRowCount() + int rowsToShow = gridAdapter.getSystemRowCount() + gridAdapter.getProfileRowCount() + gridAdapter.getServiceTargetRowCount() + gridAdapter.getCallerAndRankedTargetRowCount(); @@ -3273,7 +3274,7 @@ public class ChooserActivity extends ResolverActivity implements public int getRowCount() { return (int) ( - getContentPreviewRowCount() + getSystemRowCount() + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() @@ -3289,7 +3290,7 @@ public class ChooserActivity extends ResolverActivity implements * content preview. Not to be confused with the sticky content preview which is above the * personal and work tabs. */ - public int getContentPreviewRowCount() { + public int getSystemRowCount() { // For the tabbed case we show the sticky content preview above the tabs, // please refer to shouldShowStickyContentPreview if (shouldShowTabs()) { @@ -3299,8 +3300,7 @@ public class ChooserActivity extends ResolverActivity implements return 0; } - if (mHideContentPreview || mChooserListAdapter == null - || mChooserListAdapter.getCount() == 0) { + if (mChooserListAdapter == null || mChooserListAdapter.getCount() == 0) { return 0; } @@ -3342,7 +3342,7 @@ public class ChooserActivity extends ResolverActivity implements @Override public int getItemCount() { return (int) ( - getContentPreviewRowCount() + getSystemRowCount() + getProfileRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() @@ -3397,7 +3397,7 @@ public class ChooserActivity extends ResolverActivity implements public int getItemViewType(int position) { int count; - int countSum = (count = getContentPreviewRowCount()); + int countSum = (count = getSystemRowCount()); if (count > 0 && position < countSum) return VIEW_TYPE_CONTENT_PREVIEW; countSum += (count = getProfileRowCount()); @@ -3621,7 +3621,7 @@ public class ChooserActivity extends ResolverActivity implements } int getListPosition(int position) { - position -= getContentPreviewRowCount() + getProfileRowCount(); + position -= getSystemRowCount() + getProfileRowCount(); final int serviceCount = mChooserListAdapter.getServiceTargetCount(); final int serviceRows = (int) Math.ceil((float) serviceCount diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9b90b0a24922..48275f656b2f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2151,7 +2151,7 @@ <permission android:name="android.permission.READ_PRECISE_PHONE_STATE" android:protectionLevel="signature|privileged" /> - <!-- @SystemApi Allows read access to privileged phone state. + <!-- @SystemApi @TestApi Allows read access to privileged phone state. @hide Used internally. --> <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" android:protectionLevel="signature|privileged" /> diff --git a/data/keyboards/Vendor_2378_Product_1008.kl b/data/keyboards/Vendor_2378_Product_1008.kl index 478da03b9a78..7b19469ab6b4 100644 --- a/data/keyboards/Vendor_2378_Product_1008.kl +++ b/data/keyboards/Vendor_2378_Product_1008.kl @@ -14,6 +14,10 @@ # OnLive, Inc. OnLive Wireless Controller, USB adapter +key 164 MEDIA_PLAY_PAUSE +key 167 MEDIA_RECORD +key 168 MEDIA_REWIND +key 208 MEDIA_FAST_FORWARD key 304 BUTTON_A key 305 BUTTON_B key 307 BUTTON_X @@ -22,6 +26,7 @@ key 310 BUTTON_L1 key 311 BUTTON_R1 key 315 BUTTON_START key 314 BUTTON_SELECT +key 316 BUTTON_MODE key 317 BUTTON_THUMBL key 318 BUTTON_THUMBR diff --git a/data/keyboards/Vendor_2378_Product_100a.kl b/data/keyboards/Vendor_2378_Product_100a.kl index d9cd17120464..cb2b73afee3d 100644 --- a/data/keyboards/Vendor_2378_Product_100a.kl +++ b/data/keyboards/Vendor_2378_Product_100a.kl @@ -14,6 +14,10 @@ # OnLive, Inc. OnLive Wireless Controller +key 164 MEDIA_PLAY_PAUSE +key 167 MEDIA_RECORD +key 168 MEDIA_REWIND +key 208 MEDIA_FAST_FORWARD key 304 BUTTON_A key 305 BUTTON_B key 307 BUTTON_X @@ -22,6 +26,7 @@ key 310 BUTTON_L1 key 311 BUTTON_R1 key 315 BUTTON_START key 314 BUTTON_SELECT +key 316 BUTTON_MODE key 317 BUTTON_THUMBL key 318 BUTTON_THUMBR diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index bbd5b23471d7..64d3d92a0b8a 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -46447,7 +46447,7 @@ package android.telephony { method @Deprecated public int getPhoneCount(); method public int getPhoneType(); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PHONE_STATE}) public int getPreferredOpportunisticDataSubscription(); - method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState(); + method @Nullable @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_COARSE_LOCATION}) public android.telephony.ServiceState getServiceState(); method @Nullable public android.telephony.SignalStrength getSignalStrength(); method public int getSimCarrierId(); method @Nullable public CharSequence getSimCarrierIdName(); @@ -46470,7 +46470,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailAlphaTag(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getVoiceNetworkType(); - method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); + method @Nullable public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); method public boolean hasCarrierPrivileges(); method public boolean hasIccCard(); method @Deprecated public boolean iccCloseLogicalChannel(int); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java index 2ff667093e58..a526e6943004 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java @@ -478,6 +478,9 @@ public class UserGridRecyclerView extends RecyclerView { if (user != null) { mCarUserManagerHelper.switchToUser(user); } + if (mAddUserView != null) { + mAddUserView.setEnabled(true); + } } } diff --git a/packages/InputDevices/res/raw/keyboard_layout_turkish_f.kcm b/packages/InputDevices/res/raw/keyboard_layout_turkish_f.kcm new file mode 100644 index 000000000000..5b96da027be7 --- /dev/null +++ b/packages/InputDevices/res/raw/keyboard_layout_turkish_f.kcm @@ -0,0 +1,366 @@ +# 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. + +# +# Turkish F keyboard layout. +# + +type OVERLAY + +map key 12 SLASH +map key 13 MINUS +map key 43 COMMA +map key 51 EQUALS +map key 52 BACKSLASH +map key 53 PERIOD +map key 86 PLUS + +### ROW 1 + +key GRAVE { + label: '+' + base: '+' + shift: '*' + ralt: '\u00ac' +} + +key 1 { + label: '1' + base: '1' + shift: '!' + ralt: '\u00b9' +} + +key 2 { + label: '2' + base: '2' + shift: '"' + ralt: '\u00b2' +} + +key 3 { + label: '3' + base: '3' + shift: '^' + ralt: '#' +} + +key 4 { + label: '4' + base: '4' + shift: '$' + ralt: '\u00bc' +} + +key 5 { + label: '5' + base: '5' + shift: '%' + ralt: '\u00bd' +} + +key 6 { + label: '6' + base: '6' + shift: '&' + ralt: '\u00be' +} + +key 7 { + label: '7' + base: '7' + shift: '\'' + ralt: '{' +} + +key 8 { + label: '8' + base: '8' + shift: '(' + ralt: '[' +} + +key 9 { + label: '9' + base: '9' + shift: ')' + ralt: ']' +} + +key 0 { + label: '0' + base: '0' + shift: '=' + ralt: '}' +} + +key SLASH { + label: '/' + base: '/' + shift: '?' + ralt: '\\' +} + +key MINUS { + label: '-' + base: '-' + shift: '_' + ralt: '|' +} + +### ROW 2 + +key Q { + label: 'F' + base: 'f' + shift, capslock: 'F' + ralt: '@' +} + +key W { + label: 'G' + base: 'g' + shift, capslock: 'G' +} + +key E { + label: '\u011f' + base: '\u011f' + shift, capslock: '\u011e' +} + +key R { + label: '\u0131' + base: '\u0131' + shift, capslock: 'I' + ralt: '\u00b6' + ralt+shift, ralt+capslock: '\u00ae' +} + +key T { + label: 'O' + base: 'o' + shift, capslock: 'O' +} + +key Y { + label: 'D' + base: 'd' + shift, capslock: 'D' + ralt: '\u00a5' +} + +key U { + label: 'R' + base: 'r' + shift, capslock: 'R' +} + +key I { + label: 'N' + base: 'n' + shift, capslock: 'N' +} + +key O { + label: 'H' + base: 'h' + shift, capslock: 'H' + ralt: '\u00f8' + ralt+shift, ralt+capslock: '\u00d8' +} + +key P { + label: 'P' + base: 'p' + shift, capslock: 'P' + ralt: '\u00a3' +} + +key LEFT_BRACKET { + label: 'Q' + base: 'q' + shift, capslock: 'Q' + ralt: '"' +} + +key RIGHT_BRACKET { + label: 'W' + base: 'w' + shift, capslock: 'W' + ralt: '~' +} + +### ROW 3 + +key A { + label: '\u0075' + base: '\u0075' + shift, capslock: '\u0055' + ralt: '\u00e6' + ralt+shift, ralt+capslock: '\u00c6' +} + +key S { + label: 'i' + base: 'i' + shift, capslock: '\u0130' + ralt: '\u00df' + ralt+shift, ralt+capslock: '\u00a7' +} + +key D { + label: 'E' + base: 'e' + shift, capslock: 'E' + ralt: '\u20ac' +} + +key F { + label: 'A' + base: 'a' + shift, capslock: 'A' + ralt: '\u00aa' +} + +key G { + label: '\u00fc' + base: '\u00fc' + shift, capslock: '\u00dc' +} + +key H { + label: 'T' + base: 't' + shift, capslock: 'T' + ralt: '\u20ba' +} + +key J { + label: 'K' + base: 'k' + shift, capslock: 'K' +} + +key K { + label: 'M' + base: 'm' + shift, capslock: 'M' +} + +key L { + label: 'L' + base: 'l' + shift, capslock: 'L' +} + +key SEMICOLON { + label: 'Y' + base: 'y' + shift, capslock: 'Y' + ralt: '\u00b4' +} + +key APOSTROPHE { + label: '\u015f' + base: '\u015f' + shift, capslock: '\u015e' +} + +key COMMA { + label: 'X' + base: 'x' + shift: 'X' + ralt: '\u0060' +} + +### ROW 4 + +key PLUS { + label: '<' + base: '<' + shift: '>' + ralt: '|' + ralt+shift, ralt+capslock: '\u00a6' +} + +key Z { + label: 'J' + base: 'j' + shift, capslock: 'J' + ralt: '\u00ab' + ralt+shift, ralt+capslock: '<' +} + +key X { + label: '\u00f6' + base: '\u00f6' + shift, capslock: '\u00d6' + ralt: '\u00bb' + ralt+shift, ralt+capslock: '>' +} + +key C { + label: 'V' + base: 'v' + shift, capslock: 'V' + ralt: '\u00a2' + ralt+shift, ralt+capslock: '\u00a9' +} + +key V { + label: 'C' + base: 'c' + shift, capslock: 'C' +} + +key B { + label: '\u00e7' + base: '\u00e7' + shift, capslock: '\u00c7' +} + +key N { + label: 'Z' + base: 'z' + shift, capslock: 'Z' +} + +key M { + label: 'S' + base: 's' + shift, capslock: 'S' + ralt: '\u00b5' + ralt+shift, ralt+capslock: '\u00ba' +} + +key EQUALS { + label: 'B' + base: 'b' + shift, capslock: 'B' + ralt: '\u00d7' +} + +key BACKSLASH { + label: '.' + base: '.' + shift, capslock: ':' + ralt: '\u00f7' +} + +key PERIOD { + label: ',' + base: ',' + shift: ';' +} diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml index e95a15912397..c2585ff49a11 100644 --- a/packages/InputDevices/res/values/strings.xml +++ b/packages/InputDevices/res/values/strings.xml @@ -102,6 +102,9 @@ <!-- Turkish keyboard layout label. [CHAR LIMIT=35] --> <string name="keyboard_layout_turkish">Turkish</string> + <!-- Turkish keyboard layout label. [CHAR LIMIT=35] --> + <string name="keyboard_layout_turkish_f">Turkish F</string> + <!-- Ukrainian keyboard layout label. [CHAR LIMIT=35] --> <string name="keyboard_layout_ukrainian">Ukrainian</string> diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml index aa599ae7f2d0..d3c421da9055 100644 --- a/packages/InputDevices/res/xml/keyboard_layouts.xml +++ b/packages/InputDevices/res/xml/keyboard_layouts.xml @@ -128,6 +128,10 @@ android:label="@string/keyboard_layout_turkish" android:keyboardLayout="@raw/keyboard_layout_turkish" /> + <keyboard-layout android:name="keyboard_layout_turkish_f" + android:label="@string/keyboard_layout_turkish_f" + android:keyboardLayout="@raw/keyboard_layout_turkish_f" /> + <keyboard-layout android:name="keyboard_layout_ukrainian" android:label="@string/keyboard_layout_ukrainian" android:keyboardLayout="@raw/keyboard_layout_ukrainian" /> diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java index 6276c4e2aa7d..0cf14e3f868c 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java @@ -20,6 +20,10 @@ import static android.net.TetheringManager.TETHERING_BLUETOOTH; import static android.net.TetheringManager.TETHERING_WIFI_P2P; import static android.net.util.PrefixUtils.asIpPrefix; +import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH; +import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH; +import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; + import static java.util.Arrays.asList; import android.content.Context; @@ -37,9 +41,10 @@ import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; +import java.net.Inet4Address; import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Random; @@ -58,10 +63,6 @@ import java.util.Set; public class PrivateAddressCoordinator { public static final int PREFIX_LENGTH = 24; - private static final int MAX_UBYTE = 256; - private static final int BYTE_MASK = 0xff; - private static final byte DEFAULT_ID = (byte) 42; - // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream // address may be requested before coordinator get current upstream notification. To ensure // coordinator do not select conflict downstream prefix, mUpstreamPrefixMap would not be cleared @@ -69,22 +70,22 @@ public class PrivateAddressCoordinator { // mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprecatedUpstreams(). private final ArrayMap<Network, List<IpPrefix>> mUpstreamPrefixMap; private final ArraySet<IpServer> mDownstreams; - // IANA has reserved the following three blocks of the IP address space for private intranets: - // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 - // Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers. - private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16"; private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24"; private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24"; - private final IpPrefix mTetheringPrefix; + private final List<IpPrefix> mTetheringPrefixes; private final ConnectivityManager mConnectivityMgr; private final TetheringConfiguration mConfig; // keyed by downstream type(TetheringManager.TETHERING_*). private final SparseArray<LinkAddress> mCachedAddresses; public PrivateAddressCoordinator(Context context, TetheringConfiguration config) { + this(context, config, new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16")))); + } + + public PrivateAddressCoordinator(Context context, TetheringConfiguration config, + List<IpPrefix> prefixPools) { mDownstreams = new ArraySet<>(); mUpstreamPrefixMap = new ArrayMap<>(); - mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX); mConnectivityMgr = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE); mConfig = config; @@ -92,6 +93,8 @@ public class PrivateAddressCoordinator { // Reserved static addresses for bluetooth and wifi p2p. mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS)); mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS)); + + mTetheringPrefixes = prefixPools; } /** @@ -179,52 +182,148 @@ public class PrivateAddressCoordinator { return cachedAddress; } - // Address would be 192.168.[subAddress]/24. - final byte[] bytes = mTetheringPrefix.getRawAddress(); - final int subAddress = getRandomSubAddr(); - final int subNet = (subAddress >> 8) & BYTE_MASK; - bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff); - for (int i = 0; i < MAX_UBYTE; i++) { - final int newSubNet = (subNet + i) & BYTE_MASK; - bytes[2] = (byte) newSubNet; - - final InetAddress addr; - try { - addr = InetAddress.getByAddress(bytes); - } catch (UnknownHostException e) { - throw new IllegalStateException("Invalid address, shouldn't happen.", e); + for (IpPrefix prefixRange : mTetheringPrefixes) { + final LinkAddress newAddress = chooseDownstreamAddress(prefixRange); + if (newAddress != null) { + mDownstreams.add(ipServer); + mCachedAddresses.put(ipServer.interfaceType(), newAddress); + return newAddress; } - - if (isConflict(new IpPrefix(addr, PREFIX_LENGTH))) continue; - - mDownstreams.add(ipServer); - final LinkAddress newAddress = new LinkAddress(addr, PREFIX_LENGTH); - mCachedAddresses.put(ipServer.interfaceType(), newAddress); - return newAddress; } // No available address. return null; } - private boolean isConflict(final IpPrefix prefix) { - // Check whether this prefix is in use or conflict with any current upstream network. - return isDownstreamPrefixInUse(prefix) || isConflictWithUpstream(prefix); + private int getPrefixBaseAddress(final IpPrefix prefix) { + return inet4AddressToIntHTH((Inet4Address) prefix.getAddress()); + } + + /** + * Check whether input prefix conflict with upstream prefixes or in-use downstream prefixes. + * If yes, return one of them. + */ + private IpPrefix getConflictPrefix(final IpPrefix prefix) { + final IpPrefix upstream = getConflictWithUpstream(prefix); + if (upstream != null) return upstream; + + return getInUseDownstreamPrefix(prefix); + } + + // Get the next non-conflict sub prefix. E.g: To get next sub prefix from 10.0.0.0/8, if the + // previously selected prefix is 10.20.42.0/24(subPrefix: 0.20.42.0) and the conflicting prefix + // is 10.16.0.0/20 (10.16.0.0 ~ 10.16.15.255), then the max address under subPrefix is + // 0.16.15.255 and the next subPrefix is 0.16.16.255/24 (0.16.15.255 + 0.0.1.0). + // Note: the sub address 0.0.0.255 here is fine to be any value that it will be replaced as + // selected random sub address later. + private int getNextSubPrefix(final IpPrefix conflictPrefix, final int prefixRangeMask) { + final int suffixMask = ~prefixLengthToV4NetmaskIntHTH(conflictPrefix.getPrefixLength()); + // The largest offset within the prefix assignment block that still conflicts with + // conflictPrefix. + final int maxConflict = + (getPrefixBaseAddress(conflictPrefix) | suffixMask) & ~prefixRangeMask; + + final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH); + // Pick a sub prefix a full prefix (1 << (32 - PREFIX_LENGTH) addresses) greater than + // maxConflict. This ensures that the selected prefix never overlaps with conflictPrefix. + // There is no need to mask the result with PREFIX_LENGTH bits because this is done by + // findAvailablePrefixFromRange when it constructs the prefix. + return maxConflict + (1 << (32 - PREFIX_LENGTH)); } - /** Get random sub address value. Return value is in 0 ~ 0xffff. */ + private LinkAddress chooseDownstreamAddress(final IpPrefix prefixRange) { + // The netmask of the prefix assignment block (e.g., 0xfff00000 for 172.16.0.0/12). + final int prefixRangeMask = prefixLengthToV4NetmaskIntHTH(prefixRange.getPrefixLength()); + + // The zero address in the block (e.g., 0xac100000 for 172.16.0.0/12). + final int baseAddress = getPrefixBaseAddress(prefixRange); + + // The subnet mask corresponding to PREFIX_LENGTH. + final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH); + + // The offset within prefixRange of a randomly-selected prefix of length PREFIX_LENGTH. + // This may not be the prefix of the address returned by this method: + // - If it is already in use, the method will return an address in another prefix. + // - If all prefixes within prefixRange are in use, the method will return null. For + // example, for a /24 prefix within 172.26.0.0/12, this will be a multiple of 256 in + // [0, 1048576). In other words, a random 32-bit number with mask 0x000fff00. + // + // prefixRangeMask is required to ensure no wrapping. For example, consider: + // - prefixRange 127.0.0.0/8 + // - randomPrefixStart 127.255.255.0 + // - A conflicting prefix of 127.255.254.0/23 + // In this case without prefixRangeMask, getNextSubPrefix would return 128.0.0.0, which + // means the "start < end" check in findAvailablePrefixFromRange would not reject the prefix + // because Java doesn't have unsigned integers, so 128.0.0.0 = 0x80000000 = -2147483648 + // is less than 127.0.0.0 = 0x7f000000 = 2130706432. + // + // Additionally, it makes debug output easier to read by making the numbers smaller. + final int randomPrefixStart = getRandomInt() & ~prefixRangeMask & prefixMask; + + // A random offset within the prefix. Used to determine the local address once the prefix + // is selected. It does not result in an IPv4 address ending in .0, .1, or .255 + // For a PREFIX_LENGTH of 255, this is a number between 2 and 254. + final int subAddress = getSanitizedSubAddr(~prefixMask); + + // Find a prefix length PREFIX_LENGTH between randomPrefixStart and the end of the block, + // such that the prefix does not conflict with any upstream. + IpPrefix downstreamPrefix = findAvailablePrefixFromRange( + randomPrefixStart, (~prefixRangeMask) + 1, baseAddress, prefixRangeMask); + if (downstreamPrefix != null) return getLinkAddress(downstreamPrefix, subAddress); + + // If that failed, do the same, but between 0 and randomPrefixStart. + downstreamPrefix = findAvailablePrefixFromRange( + 0, randomPrefixStart, baseAddress, prefixRangeMask); + + return getLinkAddress(downstreamPrefix, subAddress); + } + + private LinkAddress getLinkAddress(final IpPrefix prefix, final int subAddress) { + if (prefix == null) return null; + + final InetAddress address = intToInet4AddressHTH(getPrefixBaseAddress(prefix) | subAddress); + return new LinkAddress(address, PREFIX_LENGTH); + } + + private IpPrefix findAvailablePrefixFromRange(final int start, final int end, + final int baseAddress, final int prefixRangeMask) { + int newSubPrefix = start; + while (newSubPrefix < end) { + final InetAddress address = intToInet4AddressHTH(baseAddress | newSubPrefix); + final IpPrefix prefix = new IpPrefix(address, PREFIX_LENGTH); + + final IpPrefix conflictPrefix = getConflictPrefix(prefix); + + if (conflictPrefix == null) return prefix; + + newSubPrefix = getNextSubPrefix(conflictPrefix, prefixRangeMask); + } + + return null; + } + + /** Get random int which could be used to generate random address. */ @VisibleForTesting - public int getRandomSubAddr() { - return ((new Random()).nextInt()) & 0xffff; // subNet is in 0 ~ 0xffff. + public int getRandomInt() { + return (new Random()).nextInt(); } - private byte getSanitizedAddressSuffix(final int source, byte... excluded) { - final byte subId = (byte) (source & BYTE_MASK); - for (byte value : excluded) { - if (subId == value) return DEFAULT_ID; + /** Get random subAddress and avoid selecting x.x.x.0, x.x.x.1 and x.x.x.255 address. */ + private int getSanitizedSubAddr(final int subAddrMask) { + final int randomSubAddr = getRandomInt() & subAddrMask; + // If prefix length > 30, the selecting speace would be less than 4 which may be hard to + // avoid 3 consecutive address. + if (PREFIX_LENGTH > 30) return randomSubAddr; + + // TODO: maybe it is not necessary to avoid .0, .1 and .255 address because tethering + // address would not be conflicted. This code only works because PREFIX_LENGTH is not longer + // than 24 + final int candidate = randomSubAddr & 0xff; + if (candidate == 0 || candidate == 1 || candidate == 255) { + return (randomSubAddr & 0xfffffffc) + 2; } - return subId; + return randomSubAddr; } /** Release downstream record for IpServer. */ @@ -237,14 +336,18 @@ public class PrivateAddressCoordinator { mUpstreamPrefixMap.clear(); } - private boolean isConflictWithUpstream(final IpPrefix source) { + private IpPrefix getConflictWithUpstream(final IpPrefix prefix) { for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { final List<IpPrefix> list = mUpstreamPrefixMap.valueAt(i); - for (IpPrefix target : list) { - if (isConflictPrefix(source, target)) return true; + for (IpPrefix upstream : list) { + if (isConflictPrefix(prefix, upstream)) return upstream; } } - return false; + return null; + } + + private boolean isConflictWithUpstream(final IpPrefix prefix) { + return getConflictWithUpstream(prefix) != null; } private boolean isConflictPrefix(final IpPrefix prefix1, final IpPrefix prefix2) { @@ -257,11 +360,10 @@ public class PrivateAddressCoordinator { // InUse Prefixes are prefixes of mCachedAddresses which are active downstream addresses, last // downstream addresses(reserved for next time) and static addresses(e.g. bluetooth, wifi p2p). - private boolean isDownstreamPrefixInUse(final IpPrefix prefix) { - // This class always generates downstream prefixes with the same prefix length, so - // prefixes cannot be contained in each other. They can only be equal to each other. + private IpPrefix getInUseDownstreamPrefix(final IpPrefix prefix) { for (int i = 0; i < mCachedAddresses.size(); i++) { - if (prefix.equals(asIpPrefix(mCachedAddresses.valueAt(i)))) return true; + final IpPrefix downstream = asIpPrefix(mCachedAddresses.valueAt(i)); + if (isConflictPrefix(prefix, downstream)) return downstream; } // IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include @@ -270,10 +372,10 @@ public class PrivateAddressCoordinator { final IpPrefix target = getDownstreamPrefix(downstream); if (target == null) continue; - if (isConflictPrefix(prefix, target)) return true; + if (isConflictPrefix(prefix, target)) return target; } - return false; + return null; } private IpPrefix getDownstreamPrefix(final IpServer downstream) { @@ -284,6 +386,13 @@ public class PrivateAddressCoordinator { } void dump(final IndentingPrintWriter pw) { + pw.println("mTetheringPrefixes:"); + pw.increaseIndent(); + for (IpPrefix prefix : mTetheringPrefixes) { + pw.println(prefix); + } + pw.decreaseIndent(); + pw.println("mUpstreamPrefixMap:"); pw.increaseIndent(); for (int i = 0; i < mUpstreamPrefixMap.size(); i++) { diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java index 474f4e8b603a..5a0c5b0cff5f 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -326,7 +326,7 @@ public class Tethering { // It is OK for the configuration to be passed to the PrivateAddressCoordinator at // construction time because the only part of the configuration it uses is // shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that. - mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext, mConfig); + mPrivateAddressCoordinator = mDeps.getPrivateAddressCoordinator(mContext, mConfig); // Must be initialized after tethering configuration is loaded because BpfCoordinator // constructor needs to use the configuration. diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index 131a5fbf2abe..45b914178e97 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -156,4 +156,12 @@ public abstract class TetheringDependencies { public boolean isTetheringDenied() { return TextUtils.equals(SystemProperties.get("ro.tether.denied"), "true"); } + + /** + * Get a reference to PrivateAddressCoordinator to be used by Tethering. + */ + public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx, + TetheringConfiguration cfg) { + return new PrivateAddressCoordinator(ctx, cfg); + } } diff --git a/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java index 95e36fa18f42..42a91aa9acd5 100644 --- a/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java +++ b/packages/Tethering/tests/privileged/src/android/net/ip/DadProxyTest.java @@ -17,9 +17,9 @@ package android.net.ip; import static android.system.OsConstants.IPPROTO_ICMPV6; -import static android.system.OsConstants.IPPROTO_TCP; -import static com.android.internal.util.BitUtils.uint16; +import static com.android.net.module.util.IpUtils.icmpv6Checksum; +import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -30,34 +30,29 @@ import android.content.Context; import android.net.INetd; import android.net.InetAddresses; import android.net.MacAddress; -import android.net.TestNetworkInterface; -import android.net.TestNetworkManager; import android.net.util.InterfaceParams; import android.net.util.TetheringUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; -import android.system.ErrnoException; -import android.system.Os; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.net.module.util.IpUtils; import com.android.testutils.TapPacketReader; +import com.android.testutils.TapPacketReaderRule; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.MockitoAnnotations; -import java.io.FileDescriptor; import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicReference; @RunWith(AndroidJUnit4.class) @SmallTest @@ -65,16 +60,18 @@ public class DadProxyTest { private static final int DATA_BUFFER_LEN = 4096; private static final int PACKET_TIMEOUT_MS = 5_000; - // TODO: make NetworkStackConstants accessible to this test and use the constant from there. - private static final int ETHER_SRC_ADDR_OFFSET = 6; + // Start the readers manually on a common handler shared with DadProxy, for simplicity + @Rule + public final TapPacketReaderRule mUpstreamReader = new TapPacketReaderRule( + DATA_BUFFER_LEN, false /* autoStart */); + @Rule + public final TapPacketReaderRule mTetheredReader = new TapPacketReaderRule( + DATA_BUFFER_LEN, false /* autoStart */); - private DadProxy mProxy; - TestNetworkInterface mUpstreamTestIface, mTetheredTestIface; private InterfaceParams mUpstreamParams, mTetheredParams; private HandlerThread mHandlerThread; private Handler mHandler; private TapPacketReader mUpstreamPacketReader, mTetheredPacketReader; - private FileDescriptor mUpstreamTapFd, mTetheredTapFd; private static INetd sNetd; @@ -106,12 +103,12 @@ public class DadProxyTest { @After public void tearDown() throws Exception { + mUpstreamReader.stop(); + mTetheredReader.stop(); + if (mHandlerThread != null) { - mHandler.post(mUpstreamPacketReader::stop); // Also closes the socket - mHandler.post(mTetheredPacketReader::stop); // Also closes the socket - mUpstreamTapFd = null; - mTetheredTapFd = null; mHandlerThread.quitSafely(); + mHandlerThread.join(PACKET_TIMEOUT_MS); } if (mTetheredParams != null) { @@ -120,54 +117,20 @@ public class DadProxyTest { if (mUpstreamParams != null) { sNetd.networkRemoveInterface(INetd.LOCAL_NET_ID, mUpstreamParams.name); } - - if (mUpstreamTestIface != null) { - try { - Os.close(mUpstreamTestIface.getFileDescriptor().getFileDescriptor()); - } catch (ErrnoException e) { } - } - - if (mTetheredTestIface != null) { - try { - Os.close(mTetheredTestIface.getFileDescriptor().getFileDescriptor()); - } catch (ErrnoException e) { } - } - } - - private TestNetworkInterface setupTapInterface() { - final Instrumentation inst = InstrumentationRegistry.getInstrumentation(); - AtomicReference<TestNetworkInterface> iface = new AtomicReference<>(); - - inst.getUiAutomation().adoptShellPermissionIdentity(); - try { - final TestNetworkManager tnm = (TestNetworkManager) inst.getContext().getSystemService( - Context.TEST_NETWORK_SERVICE); - iface.set(tnm.createTapInterface()); - } finally { - inst.getUiAutomation().dropShellPermissionIdentity(); - } - - return iface.get(); } private void setupTapInterfaces() { // Create upstream test iface. - mUpstreamTestIface = setupTapInterface(); - mUpstreamParams = InterfaceParams.getByName(mUpstreamTestIface.getInterfaceName()); + mUpstreamReader.start(mHandler); + mUpstreamParams = InterfaceParams.getByName(mUpstreamReader.iface.getInterfaceName()); assertNotNull(mUpstreamParams); - mUpstreamTapFd = mUpstreamTestIface.getFileDescriptor().getFileDescriptor(); - mUpstreamPacketReader = new TapPacketReader(mHandler, mUpstreamTapFd, - DATA_BUFFER_LEN); - mHandler.post(mUpstreamPacketReader::start); + mUpstreamPacketReader = mUpstreamReader.getReader(); // Create tethered test iface. - mTetheredTestIface = setupTapInterface(); - mTetheredParams = InterfaceParams.getByName(mTetheredTestIface.getInterfaceName()); + mTetheredReader.start(mHandler); + mTetheredParams = InterfaceParams.getByName(mTetheredReader.getIface().getInterfaceName()); assertNotNull(mTetheredParams); - mTetheredTapFd = mTetheredTestIface.getFileDescriptor().getFileDescriptor(); - mTetheredPacketReader = new TapPacketReader(mHandler, mTetheredTapFd, - DATA_BUFFER_LEN); - mHandler.post(mTetheredPacketReader::start); + mTetheredPacketReader = mTetheredReader.getReader(); } private static final int IPV6_HEADER_LEN = 40; @@ -177,31 +140,6 @@ public class DadProxyTest { private static final int ICMPV6_CHECKSUM_OFFSET = 2; private static final int ETHER_TYPE_IPV6 = 0x86dd; - // TODO: move the IpUtils code to frameworks/lib/net and link it statically. - private static int checksumFold(int sum) { - while (sum > 0xffff) { - sum = (sum >> 16) + (sum & 0xffff); - } - return sum; - } - - // TODO: move the IpUtils code to frameworks/lib/net and link it statically. - private static short checksumAdjust(short checksum, short oldWord, short newWord) { - checksum = (short) ~checksum; - int tempSum = checksumFold(uint16(checksum) + uint16(newWord) + 0xffff - uint16(oldWord)); - return (short) ~tempSum; - } - - // TODO: move the IpUtils code to frameworks/lib/net and link it statically. - private static short icmpv6Checksum(ByteBuffer buf, int ipOffset, int transportOffset, - int transportLen) { - // The ICMPv6 checksum is the same as the TCP checksum, except the pseudo-header uses - // 58 (ICMPv6) instead of 6 (TCP). Calculate the TCP checksum, and then do an incremental - // checksum adjustment for the change in the next header byte. - short checksum = IpUtils.tcpChecksum(buf, ipOffset, transportOffset, transportLen); - return checksumAdjust(checksum, (short) IPPROTO_TCP, (short) IPPROTO_ICMPV6); - } - private static ByteBuffer createDadPacket(int type) { // Refer to buildArpPacket() int icmpLen = ICMPV6_NA_NS_LEN diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java index 191eb6e71149..86e6f11659c6 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java @@ -51,6 +51,9 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.Arrays; + @RunWith(AndroidJUnit4.class) @SmallTest public final class PrivateAddressCoordinatorTest { @@ -70,7 +73,17 @@ public final class PrivateAddressCoordinatorTest { private final Network mWifiNetwork = new Network(1); private final Network mMobileNetwork = new Network(2); private final Network mVpnNetwork = new Network(3); - private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork}; + private final Network mMobileNetwork2 = new Network(4); + private final Network mMobileNetwork3 = new Network(5); + private final Network mMobileNetwork4 = new Network(6); + private final Network mMobileNetwork5 = new Network(7); + private final Network mMobileNetwork6 = new Network(8); + private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork, mVpnNetwork, + mMobileNetwork2, mMobileNetwork3, mMobileNetwork4, mMobileNetwork5, mMobileNetwork6}; + private final ArrayList<IpPrefix> mTetheringPrefixes = new ArrayList<>(Arrays.asList( + new IpPrefix("192.168.0.0/16"), + new IpPrefix("172.16.0.0/12"), + new IpPrefix("10.0.0.0/8"))); private void setUpIpServers() throws Exception { when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB); @@ -87,7 +100,8 @@ public final class PrivateAddressCoordinatorTest { when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks); when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false); setUpIpServers(); - mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig)); + mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig, + mTetheringPrefixes)); } @Test @@ -117,28 +131,28 @@ public final class PrivateAddressCoordinatorTest { @Test public void testSanitizedAddress() throws Exception { int fakeSubAddr = 0x2b00; // 43.0. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); - assertEquals(new LinkAddress("192.168.43.42/24"), actualAddress); + assertEquals(new LinkAddress("192.168.43.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2d01; // 45.1. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); - assertEquals(new LinkAddress("192.168.45.42/24"), actualAddress); + assertEquals(new LinkAddress("192.168.45.2/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2eff; // 46.255. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); - assertEquals(new LinkAddress("192.168.46.42/24"), actualAddress); + assertEquals(new LinkAddress("192.168.46.254/24"), actualAddress); mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); fakeSubAddr = 0x2f05; // 47.5. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeSubAddr); actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress); @@ -148,7 +162,7 @@ public final class PrivateAddressCoordinatorTest { @Test public void testReservedPrefix() throws Exception { // - Test bluetooth prefix is reserved. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mBluetoothAddress.getAddress().getAddress())); final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, false /* useLastAddress */); @@ -157,7 +171,7 @@ public final class PrivateAddressCoordinatorTest { mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer); // - Test previous enabled hotspot prefix(cached prefix) is reserved. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(hotspotAddress.getAddress().getAddress())); final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mUsbIpServer, false /* useLastAddress */); @@ -167,7 +181,7 @@ public final class PrivateAddressCoordinatorTest { mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); // - Test wifi p2p prefix is reserved. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); final LinkAddress etherAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mEthernetIpServer, false /* useLastAddress */); @@ -182,7 +196,7 @@ public final class PrivateAddressCoordinatorTest { public void testRequestLastDownstreamAddress() throws Exception { final int fakeHotspotSubAddr = 0x2b05; final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, true /* useLastAddress */); assertEquals("Wrong wifi prefix: ", predefinedPrefix, asIpPrefix(hotspotAddress)); @@ -196,7 +210,7 @@ public final class PrivateAddressCoordinatorTest { mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer); final int newFakeSubAddr = 0x3c05; - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); final LinkAddress newHotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, true /* useLastAddress */); @@ -229,11 +243,10 @@ public final class PrivateAddressCoordinatorTest { @Test public void testNoConflictUpstreamPrefix() throws Exception { - final int fakeHotspotSubId = 43; - final int fakeHotspotSubAddr = 0x2b05; + final int fakeHotspotSubAddr = 0x2b05; // 43.5 final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24"); // Force always get subAddress "43.5" for conflict testing. - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr); + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(fakeHotspotSubAddr); // - Enable hotspot with prefix 192.168.43.0/24 final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress( mHotspotIpServer, true /* useLastAddress */); @@ -312,6 +325,209 @@ public final class PrivateAddressCoordinatorTest { assertEquals(predefinedPrefix, ethPrefix); } + @Test + public void testChooseAvailablePrefix() throws Exception { + final int randomAddress = 0x8605; // 134.5 + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); + final LinkAddress addr0 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.134.5. + assertEquals("Wrong prefix: ", new LinkAddress("192.168.134.5/24"), addr0); + when(mHotspotIpServer.getAddress()).thenReturn(addr0); + final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.134.13/26"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); + + // Check whether return address is next prefix of 192.168.134.0/24. + final LinkAddress addr1 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.135.5/24"), addr1); + when(mHotspotIpServer.getAddress()).thenReturn(addr1); + final UpstreamNetworkState wifiUpstream2 = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.149.16/19"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream2); + + + // The conflict range is 128 ~ 159, so the address is 192.168.160.5/24. + final LinkAddress addr2 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.160.5/24"), addr2); + when(mHotspotIpServer.getAddress()).thenReturn(addr2); + final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("192.168.129.53/18"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + // Update another conflict upstream which is covered by the previous one (but not the first + // one) and verify whether this would affect the result. + final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2, + new LinkAddress("192.168.170.7/19"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream2); + + // The conflict range are 128 ~ 159 and 159 ~ 191, so the address is 192.168.192.5/24. + final LinkAddress addr3 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.192.5/24"), addr3); + when(mHotspotIpServer.getAddress()).thenReturn(addr3); + final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, + new LinkAddress("192.168.188.133/17"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream3); + + // Conflict range: 128 ~ 255. The next available address is 192.168.0.5 because + // 192.168.134/24 ~ 192.168.255.255/24 is not available. + final LinkAddress addr4 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.0.5/24"), addr4); + when(mHotspotIpServer.getAddress()).thenReturn(addr4); + final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, + new LinkAddress("192.168.3.59/21"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream4); + + // Conflict ranges: 128 ~ 255 and 0 ~ 7, so the address is 192.168.8.5/24. + final LinkAddress addr5 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr5); + when(mHotspotIpServer.getAddress()).thenReturn(addr5); + final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, + new LinkAddress("192.168.68.43/21"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream5); + + // Update an upstream that does *not* conflict, check whether return the same address + // 192.168.5/24. + final LinkAddress addr6 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.8.5/24"), addr6); + when(mHotspotIpServer.getAddress()).thenReturn(addr6); + final UpstreamNetworkState mobileUpstream6 = buildUpstreamNetworkState(mMobileNetwork6, + new LinkAddress("192.168.10.97/21"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream6); + + // Conflict ranges: 0 ~ 15 and 128 ~ 255, so the address is 192.168.16.5/24. + final LinkAddress addr7 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.16.5/24"), addr7); + when(mHotspotIpServer.getAddress()).thenReturn(addr7); + final UpstreamNetworkState mobileUpstream7 = buildUpstreamNetworkState(mMobileNetwork6, + new LinkAddress("192.168.0.0/17"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream7); + + // Choose prefix from next range(172.16.0.0/12) when no available prefix in 192.168.0.0/16. + final LinkAddress addr8 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.134.5/24"), addr8); + when(mHotspotIpServer.getAddress()).thenReturn(addr6); + } + + @Test + public void testChoosePrefixFromDifferentRanges() throws Exception { + final int randomAddress = 0x1f2b2a; // 31.43.42 + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn(randomAddress); + final LinkAddress classC1 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + // Check whether return address is prefix 192.168.0.0/16 + subAddress 0.0.43.42. + assertEquals("Wrong prefix: ", new LinkAddress("192.168.43.42/24"), classC1); + when(mHotspotIpServer.getAddress()).thenReturn(classC1); + final UpstreamNetworkState wifiUpstream = buildUpstreamNetworkState(mWifiNetwork, + new LinkAddress("192.168.88.23/17"), null, + makeNetworkCapabilities(TRANSPORT_WIFI)); + mPrivateAddressCoordinator.updateUpstreamPrefix(wifiUpstream); + verifyNotifyConflictAndRelease(mHotspotIpServer); + + // Check whether return address is next address of prefix 192.168.128.0/17. + final LinkAddress classC2 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("192.168.128.42/24"), classC2); + when(mHotspotIpServer.getAddress()).thenReturn(classC2); + final UpstreamNetworkState mobileUpstream = buildUpstreamNetworkState(mMobileNetwork, + new LinkAddress("192.1.2.3/8"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream); + verifyNotifyConflictAndRelease(mHotspotIpServer); + + // Check whether return address is under prefix 172.16.0.0/12. + final LinkAddress classB1 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.31.43.42/24"), classB1); + when(mHotspotIpServer.getAddress()).thenReturn(classB1); + final UpstreamNetworkState mobileUpstream2 = buildUpstreamNetworkState(mMobileNetwork2, + new LinkAddress("172.28.123.100/14"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream2); + verifyNotifyConflictAndRelease(mHotspotIpServer); + + // 172.28.0.0 ~ 172.31.255.255 is not available. + // Check whether return address is next address of prefix 172.16.0.0/14. + final LinkAddress classB2 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.0.42/24"), classB2); + when(mHotspotIpServer.getAddress()).thenReturn(classB2); + + // Check whether new downstream is next address of address 172.16.0.42/24. + final LinkAddress classB3 = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.1.42/24"), classB3); + when(mUsbIpServer.getAddress()).thenReturn(classB3); + final UpstreamNetworkState mobileUpstream3 = buildUpstreamNetworkState(mMobileNetwork3, + new LinkAddress("172.16.0.1/24"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream3); + verifyNotifyConflictAndRelease(mHotspotIpServer); + verify(mUsbIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + + // Check whether return address is next address of prefix 172.16.1.42/24. + final LinkAddress classB4 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.16.2.42/24"), classB4); + when(mHotspotIpServer.getAddress()).thenReturn(classB4); + final UpstreamNetworkState mobileUpstream4 = buildUpstreamNetworkState(mMobileNetwork4, + new LinkAddress("172.16.0.1/13"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream4); + verifyNotifyConflictAndRelease(mHotspotIpServer); + verifyNotifyConflictAndRelease(mUsbIpServer); + + // Check whether return address is next address of prefix 172.16.0.1/13. + final LinkAddress classB5 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.24.0.42/24"), classB5); + when(mHotspotIpServer.getAddress()).thenReturn(classB5); + // Check whether return address is next address of prefix 172.24.0.42/24. + final LinkAddress classB6 = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("172.24.1.42/24"), classB6); + when(mUsbIpServer.getAddress()).thenReturn(classB6); + final UpstreamNetworkState mobileUpstream5 = buildUpstreamNetworkState(mMobileNetwork5, + new LinkAddress("172.24.0.1/12"), null, + makeNetworkCapabilities(TRANSPORT_CELLULAR)); + mPrivateAddressCoordinator.updateUpstreamPrefix(mobileUpstream5); + verifyNotifyConflictAndRelease(mHotspotIpServer); + verifyNotifyConflictAndRelease(mUsbIpServer); + + // Check whether return address is prefix 10.0.0.0/8 + subAddress 0.31.43.42. + final LinkAddress classA1 = mPrivateAddressCoordinator.requestDownstreamAddress( + mHotspotIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("10.31.43.42/24"), classA1); + when(mHotspotIpServer.getAddress()).thenReturn(classA1); + // Check whether new downstream is next address of address 10.31.43.42/24. + final LinkAddress classA2 = mPrivateAddressCoordinator.requestDownstreamAddress( + mUsbIpServer, true/* useLastAddress */); + assertEquals("Wrong prefix: ", new LinkAddress("10.31.44.42/24"), classA2); + } + + private void verifyNotifyConflictAndRelease(final IpServer ipServer) throws Exception { + verify(ipServer).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT); + mPrivateAddressCoordinator.releaseDownstream(ipServer); + reset(ipServer); + setUpIpServers(); + } + private int getSubAddress(final byte... ipv4Address) { assertEquals(4, ipv4Address.length); @@ -330,7 +546,7 @@ public final class PrivateAddressCoordinatorTest { @Test public void testEnableLegacyWifiP2PAddress() throws Exception { - when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn( + when(mPrivateAddressCoordinator.getRandomInt()).thenReturn( getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress())); // No matter #shouldEnableWifiP2pDedicatedIp() is enabled or not, legacy wifi p2p prefix // is resevered. diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index df570206e389..20e94b256ad1 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -24,6 +24,9 @@ import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; +import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.RouteInfo.RTN_UNICAST; import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; @@ -179,6 +182,7 @@ public class TetheringTest { private static final String TEST_P2P_IFNAME = "test_p2p-p2p0-0"; private static final String TEST_NCM_IFNAME = "test_ncm0"; private static final String TEST_ETH_IFNAME = "test_eth0"; + private static final String TEST_BT_IFNAME = "test_pan0"; private static final String TETHERING_NAME = "Tethering"; private static final String[] PROVISIONING_APP_NAME = {"some", "app"}; private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app"; @@ -230,6 +234,7 @@ public class TetheringTest { private TetheringConfiguration mConfig; private EntitlementManager mEntitleMgr; private OffloadController mOffloadCtrl; + private PrivateAddressCoordinator mPrivateAddressCoordinator; private class TestContext extends BroadcastInterceptingContext { TestContext(Context base) { @@ -446,6 +451,18 @@ public class TetheringTest { public boolean isTetheringDenied() { return false; } + + + @Override + public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx, + TetheringConfiguration cfg) { + final ArrayList<IpPrefix> prefixPool = new ArrayList<>(Arrays.asList( + new IpPrefix("192.168.0.0/16"), + new IpPrefix("172.16.0.0/12"), + new IpPrefix("10.0.0.0/8"))); + mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(ctx, cfg, prefixPool)); + return mPrivateAddressCoordinator; + } } private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4, @@ -1875,27 +1892,36 @@ public class TetheringTest { sendConfigurationChanged(); } - private static UpstreamNetworkState buildV4WifiUpstreamState(final String ipv4Address, - final int prefixLength, final Network network) { + private static UpstreamNetworkState buildV4UpstreamState(final LinkAddress address, + final Network network, final String iface, final int transportType) { final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(TEST_WIFI_IFNAME); + prop.setInterfaceName(iface); - prop.addLinkAddress( - new LinkAddress(InetAddresses.parseNumericAddress(ipv4Address), - prefixLength)); + prop.addLinkAddress(address); final NetworkCapabilities capabilities = new NetworkCapabilities() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + .addTransportType(transportType); return new UpstreamNetworkState(prop, capabilities, network); } + private void updateV4Upstream(final LinkAddress ipv4Address, final Network network, + final String iface, final int transportType) { + final UpstreamNetworkState upstream = buildV4UpstreamState(ipv4Address, network, iface, + transportType); + mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage( + Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK, + UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, + 0, + upstream); + mLooper.dispatchAll(); + } + @Test public void testHandleIpConflict() throws Exception { final Network wifiNetwork = new Network(200); final Network[] allNetworks = { wifiNetwork }; when(mCm.getAllNetworks()).thenReturn(allNetworks); - UpstreamNetworkState upstreamNetwork = null; - runUsbTethering(upstreamNetwork); + runUsbTethering(null); final ArgumentCaptor<InterfaceConfigurationParcel> ifaceConfigCaptor = ArgumentCaptor.forClass(InterfaceConfigurationParcel.class); verify(mNetd).interfaceSetCfg(ifaceConfigCaptor.capture()); @@ -1903,13 +1929,10 @@ public class TetheringTest { verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( any(), any()); reset(mNetd, mUsbManager); - upstreamNetwork = buildV4WifiUpstreamState(ipv4Address, 30, wifiNetwork); - mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage( - Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK, - UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, - 0, - upstreamNetwork); - mLooper.dispatchAll(); + + // Cause a prefix conflict by assigning a /30 out of the downstream's /24 to the upstream. + updateV4Upstream(new LinkAddress(InetAddresses.parseNumericAddress(ipv4Address), 30), + wifiNetwork, TEST_WIFI_IFNAME, TRANSPORT_WIFI); // verify turn off usb tethering verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); mTethering.interfaceRemoved(TEST_USB_IFNAME); @@ -1921,9 +1944,10 @@ public class TetheringTest { @Test public void testNoAddressAvailable() throws Exception { final Network wifiNetwork = new Network(200); - final Network[] allNetworks = { wifiNetwork }; + final Network btNetwork = new Network(201); + final Network mobileNetwork = new Network(202); + final Network[] allNetworks = { wifiNetwork, btNetwork, mobileNetwork }; when(mCm.getAllNetworks()).thenReturn(allNetworks); - final String upstreamAddress = "192.168.0.100"; runUsbTethering(null); verify(mDhcpServer, timeout(DHCPSERVER_START_TIMEOUT_MS).times(1)).startWithCallbacks( any(), any()); @@ -1940,13 +1964,13 @@ public class TetheringTest { mLooper.dispatchAll(); reset(mUsbManager, mEm); - final UpstreamNetworkState upstreamNetwork = buildV4WifiUpstreamState( - upstreamAddress, 16, wifiNetwork); - mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage( - Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK, - UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES, - 0, - upstreamNetwork); + updateV4Upstream(new LinkAddress("192.168.0.100/16"), wifiNetwork, TEST_WIFI_IFNAME, + TRANSPORT_WIFI); + updateV4Upstream(new LinkAddress("172.16.0.0/12"), btNetwork, TEST_BT_IFNAME, + TRANSPORT_BLUETOOTH); + updateV4Upstream(new LinkAddress("10.0.0.0/8"), mobileNetwork, TEST_MOBILE_IFNAME, + TRANSPORT_CELLULAR); + mLooper.dispatchAll(); // verify turn off usb tethering verify(mUsbManager).setCurrentFunctions(UsbManager.FUNCTION_NONE); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b59f7645445d..bb9f6d2c8354 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -140,6 +140,7 @@ import android.net.util.LinkPropertiesUtils.CompareOrUpdateResult; import android.net.util.LinkPropertiesUtils.CompareResult; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; +import android.os.BasicShellCommandHandler; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -156,11 +157,8 @@ import android.os.PersistableBundle; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; -import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.ServiceSpecificException; -import android.os.ShellCallback; -import android.os.ShellCommand; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; @@ -7658,14 +7656,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out, - FileDescriptor err, @NonNull String[] args, ShellCallback callback, - @NonNull ResultReceiver resultReceiver) { - (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver); + public int handleShellCommand(@NonNull ParcelFileDescriptor in, + @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, + @NonNull String[] args) { + return new ShellCmd().exec(this, in.getFileDescriptor(), out.getFileDescriptor(), + err.getFileDescriptor(), args); } - private class ShellCmd extends ShellCommand { - + private class ShellCmd extends BasicShellCommandHandler { @Override public int onCommand(String cmd) { if (cmd == null) { diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java index 6bc1a570b7c0..0f4c94bc8d4f 100644 --- a/services/core/java/com/android/server/MountServiceIdler.java +++ b/services/core/java/com/android/server/MountServiceIdler.java @@ -113,6 +113,7 @@ public class MountServiceIdler extends JobService { JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService); builder.setRequiresDeviceIdle(true); builder.setRequiresBatteryNotLow(true); + builder.setRequiresCharging(true); builder.setMinimumLatency(nextScheduleTime); tm.schedule(builder.build()); } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 2f15918d3064..6c7f235dec6f 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -2152,7 +2152,11 @@ public class Vpn { break; } - // Prepare arguments for mtpd. + // Prepare arguments for mtpd. MTU/MRU calculated conservatively. Only IPv4 supported + // because LegacyVpn. + // 1500 - 60 (Carrier-internal IPv6 + UDP + GTP) - 10 (PPP) - 16 (L2TP) - 8 (UDP) + // - 77 (IPsec w/ SHA-2 512, 256b trunc-len, AES-CBC) - 8 (UDP encap) - 20 (IPv4) + // - 28 (464xlat) String[] mtpd = null; switch (profile.type) { case VpnProfile.TYPE_PPTP: @@ -2160,7 +2164,7 @@ public class Vpn { iface, "pptp", profile.server, "1723", "name", profile.username, "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute", - "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", + "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270", (profile.mppe ? "+mppe" : "nomppe"), }; break; @@ -2170,7 +2174,7 @@ public class Vpn { iface, "l2tp", profile.server, "1701", profile.l2tpSecret, "name", profile.username, "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute", - "usepeerdns", "idle", "1800", "mtu", "1400", "mru", "1400", + "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270", }; break; } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 2d7e79a7073c..a31aacbde46f 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -3867,7 +3867,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // quick check: if this uid doesn't have INTERNET permission, it // doesn't have network access anyway, so it is a waste to mess // with it here. - if (hasInternetPermissionUL(uid)) { + if (hasInternetPermissionUL(uid) && !isUidForegroundOnRestrictPowerUL(uid)) { uidRules.put(uid, FIREWALL_RULE_DENY); } } diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index d202a2a60738..5646c752fc90 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -30,6 +30,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; @@ -94,39 +95,41 @@ public class NetworkStatsSubscriptionsMonitor extends // also needed to track CBRS. final List<Integer> newSubs = getActiveSubIdList(mSubscriptionManager); - for (final int subId : newSubs) { - final RatTypeListener match = CollectionUtils.find(mRatListeners, - it -> it.mSubId == subId); - if (match != null) continue; - - // Create listener for every newly added sub. Also store subscriberId into it to - // prevent binder call to telephony when querying RAT. If the subscriberId is empty - // for any reason, such as SIM PIN locked, skip registration. - // SubscriberId will be unavailable again if 1. modem crashed 2. reboot - // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized - // with active sub list once all subscriberIds are ready. - final String subscriberId = mTeleManager.getSubscriberId(subId); - if (TextUtils.isEmpty(subscriberId)) { - Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub " - + subId + ", skip listener registration"); + // IMSI is needed for every newly added sub. Listener stores subscriberId into it to + // prevent binder call to telephony when querying RAT. Keep listener registration with empty + // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported + // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration. + final List<Pair<Integer, String>> filteredNewSubs = + CollectionUtils.mapNotNull(newSubs, subId -> { + final String subscriberId = mTeleManager.getSubscriberId(subId); + return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId); + }); + + for (final Pair<Integer, String> sub : filteredNewSubs) { + // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be + // suddenly change regardless of subId, such as switch IMSI feature in modem side. + // If that happens, register new listener with new IMSI and remove old one later. + if (CollectionUtils.find(mRatListeners, + it -> it.equalsKey(sub.first, sub.second)) != null) { continue; } + final RatTypeListener listener = - new RatTypeListener(mExecutor, this, subId, subscriberId); + new RatTypeListener(mExecutor, this, sub.first, sub.second); mRatListeners.add(listener); // Register listener to the telephony manager that associated with specific sub. - mTeleManager.createForSubscriptionId(subId) + mTeleManager.createForSubscriptionId(sub.first) .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); - Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId); + Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first); } for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { - // If the new list contains the subId of the listener, keeps it. - final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId); - if (match != null) continue; - - handleRemoveRatTypeListener(listener); + // If there is no subId and IMSI matched the listener, removes it. + if (CollectionUtils.find(filteredNewSubs, + it -> listener.equalsKey(it.first, it.second)) == null) { + handleRemoveRatTypeListener(listener); + } } } @@ -232,5 +235,9 @@ public class NetworkStatsSubscriptionsMonitor extends public int getSubId() { return mSubId; } + + boolean equalsKey(int subId, @NonNull String subscriberId) { + return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId); + } } } diff --git a/services/core/java/com/android/server/vcn/OWNERS b/services/core/java/com/android/server/vcn/OWNERS new file mode 100644 index 000000000000..33b9f0f75f81 --- /dev/null +++ b/services/core/java/com/android/server/vcn/OWNERS @@ -0,0 +1,7 @@ +set noparent + +benedictwong@google.com +ckesting@google.com +evitayan@google.com +nharold@google.com +jchalard@google.com
\ No newline at end of file diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c6b93d6ca4f4..0da47ca90f5e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -480,38 +480,38 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final int STATUS_BAR_DISABLE2_MASK = StatusBarManager.DISABLE2_QUICK_SETTINGS; - private static final Set<String> SECURE_SETTINGS_WHITELIST; - private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_WHITELIST; - private static final Set<String> GLOBAL_SETTINGS_WHITELIST; + private static final Set<String> SECURE_SETTINGS_ALLOWLIST; + private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST; + private static final Set<String> GLOBAL_SETTINGS_ALLOWLIST; private static final Set<String> GLOBAL_SETTINGS_DEPRECATED; - private static final Set<String> SYSTEM_SETTINGS_WHITELIST; + private static final Set<String> SYSTEM_SETTINGS_ALLOWLIST; private static final Set<Integer> DA_DISALLOWED_POLICIES; // A collection of user restrictions that are deprecated and should simply be ignored. private static final Set<String> DEPRECATED_USER_RESTRICTIONS; private static final String AB_DEVICE_KEY = "ro.build.ab_update"; static { - SECURE_SETTINGS_WHITELIST = new ArraySet<>(); - SECURE_SETTINGS_WHITELIST.add(Settings.Secure.DEFAULT_INPUT_METHOD); - SECURE_SETTINGS_WHITELIST.add(Settings.Secure.SKIP_FIRST_USE_HINTS); - SECURE_SETTINGS_WHITELIST.add(Settings.Secure.INSTALL_NON_MARKET_APPS); - - SECURE_SETTINGS_DEVICEOWNER_WHITELIST = new ArraySet<>(); - SECURE_SETTINGS_DEVICEOWNER_WHITELIST.addAll(SECURE_SETTINGS_WHITELIST); - SECURE_SETTINGS_DEVICEOWNER_WHITELIST.add(Settings.Secure.LOCATION_MODE); - - GLOBAL_SETTINGS_WHITELIST = new ArraySet<>(); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_ENABLED); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_WIFI_ENABLED); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME_ZONE); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DATA_ROAMING); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_SLEEP_POLICY); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.PRIVATE_DNS_MODE); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.PRIVATE_DNS_SPECIFIER); + SECURE_SETTINGS_ALLOWLIST = new ArraySet<>(); + SECURE_SETTINGS_ALLOWLIST.add(Settings.Secure.DEFAULT_INPUT_METHOD); + SECURE_SETTINGS_ALLOWLIST.add(Settings.Secure.SKIP_FIRST_USE_HINTS); + SECURE_SETTINGS_ALLOWLIST.add(Settings.Secure.INSTALL_NON_MARKET_APPS); + + SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST = new ArraySet<>(); + SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST.addAll(SECURE_SETTINGS_ALLOWLIST); + SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST.add(Settings.Secure.LOCATION_MODE); + + GLOBAL_SETTINGS_ALLOWLIST = new ArraySet<>(); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_ENABLED); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_WIFI_ENABLED); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME_ZONE); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.DATA_ROAMING); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_SLEEP_POLICY); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_MODE); + GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_SPECIFIER); GLOBAL_SETTINGS_DEPRECATED = new ArraySet<>(); GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.BLUETOOTH_ON); @@ -520,11 +520,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.NETWORK_PREFERENCE); GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON); - SYSTEM_SETTINGS_WHITELIST = new ArraySet<>(); - SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS); - SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS_FLOAT); - SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_BRIGHTNESS_MODE); - SYSTEM_SETTINGS_WHITELIST.add(Settings.System.SCREEN_OFF_TIMEOUT); + SYSTEM_SETTINGS_ALLOWLIST = new ArraySet<>(); + SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_BRIGHTNESS); + SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_BRIGHTNESS_FLOAT); + SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_BRIGHTNESS_MODE); + SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_OFF_TIMEOUT); DA_DISALLOWED_POLICIES = new ArraySet<>(); DA_DISALLOWED_POLICIES.add(DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA); @@ -1231,13 +1231,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { String startUserSessionMessage = null; String endUserSessionMessage = null; - // The whitelist of packages that can access cross profile calendar APIs. - // This whitelist should be in default an empty list, which indicates that no package - // is whitelisted. + // The allowlist of packages that can access cross profile calendar APIs. + // This allowlist should be in default an empty list, which indicates that no package + // is allowed. List<String> mCrossProfileCalendarPackages = Collections.emptyList(); - // The whitelist of packages that the admin has enabled to be able to request consent from - // the user to communicate cross-profile. By default, no packages are whitelisted, which is + // The allowlist of packages that the admin has enabled to be able to request consent from + // the user to communicate cross-profile. By default, no packages are allowed, which is // represented as an empty list. List<String> mCrossProfilePackages = Collections.emptyList(); @@ -2818,7 +2818,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { @Override - public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, + public void send(int code, Intent intent, String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { final int status = intent.getIntExtra( PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); @@ -7067,7 +7067,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { */ @Override public boolean setAlwaysOnVpnPackage(ComponentName who, String vpnPackage, boolean lockdown, - List<String> lockdownWhitelist) + List<String> lockdownAllowlist) throws SecurityException { enforceProfileOrDeviceOwner(who); @@ -7079,10 +7079,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, vpnPackage); } - if (vpnPackage != null && lockdown && lockdownWhitelist != null) { - for (String packageName : lockdownWhitelist) { + if (vpnPackage != null && lockdown && lockdownAllowlist != null) { + for (String packageName : lockdownAllowlist) { if (!isPackageInstalledForUser(packageName, userId)) { - Slog.w(LOG_TAG, "Non-existent package in VPN whitelist: " + packageName); + Slog.w(LOG_TAG, "Non-existent package in VPN allowlist: " + packageName); throw new ServiceSpecificException( DevicePolicyManager.ERROR_VPN_PACKAGE_NOT_FOUND, packageName); } @@ -7090,7 +7090,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } // If some package is uninstalled after the check above, it will be ignored by CM. if (!mInjector.getConnectivityManager().setAlwaysOnVpnPackageForUser( - userId, vpnPackage, lockdown, lockdownWhitelist)) { + userId, vpnPackage, lockdown, lockdownAllowlist)) { throw new UnsupportedOperationException(); } DevicePolicyEventLogger @@ -7098,7 +7098,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .setAdmin(who) .setStrings(vpnPackage) .setBoolean(lockdown) - .setInt(lockdownWhitelist != null ? lockdownWhitelist.size() : 0) + .setInt(lockdownAllowlist != null ? lockdownAllowlist.size() : 0) .write(); }); synchronized (getLockObject()) { @@ -7151,7 +7151,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override - public List<String> getAlwaysOnVpnLockdownWhitelist(ComponentName admin) + public List<String> getAlwaysOnVpnLockdownAllowlist(ComponentName admin) throws SecurityException { enforceProfileOrDeviceOwner(admin); @@ -11911,7 +11911,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return; } - if (!GLOBAL_SETTINGS_WHITELIST.contains(setting) + if (!GLOBAL_SETTINGS_ALLOWLIST.contains(setting) && !UserManager.isDeviceInDemoMode(mContext)) { throw new SecurityException(String.format( "Permission denial: device owners cannot update %1$s", setting)); @@ -11939,7 +11939,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - if (!SYSTEM_SETTINGS_WHITELIST.contains(setting)) { + if (!SYSTEM_SETTINGS_ALLOWLIST.contains(setting)) { throw new SecurityException(String.format( "Permission denial: device owners cannot update %1$s", setting)); } @@ -12083,12 +12083,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); if (isDeviceOwner(who, callingUserId)) { - if (!SECURE_SETTINGS_DEVICEOWNER_WHITELIST.contains(setting) + if (!SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST.contains(setting) && !isCurrentUserDemo()) { throw new SecurityException(String.format( "Permission denial: Device owners cannot update %1$s", setting)); } - } else if (!SECURE_SETTINGS_WHITELIST.contains(setting) && !isCurrentUserDemo()) { + } else if (!SECURE_SETTINGS_ALLOWLIST.contains(setting) && !isCurrentUserDemo()) { throw new SecurityException(String.format( "Permission denial: Profile owners cannot update %1$s", setting)); } @@ -13859,7 +13859,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) { // As the caller is the system, it must specify the component name of the profile owner - // as a sanity / safety check. + // as a safety check. Objects.requireNonNull(who); if (!mHasFeature) { @@ -13895,7 +13895,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @GuardedBy("getLockObject()") private void markProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked( ComponentName who, int userId) { - // Sanity check: Make sure that the user has a profile owner and that the specified + // Make sure that the user has a profile owner and that the specified // component is the profile owner of that user. if (!isProfileOwner(who, userId)) { throw new IllegalArgumentException(String.format( diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index a6d72450156f..9f16543c410e 100755 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -966,6 +966,32 @@ public final class Call { /** * Gets the verification status for the phone number of an incoming call as identified in * ATIS-1000082. + * <p> + * For incoming calls, the number verification status indicates whether the device was + * able to verify the authenticity of the calling number using the STIR process outlined + * in ATIS-1000082. {@link Connection#VERIFICATION_STATUS_NOT_VERIFIED} indicates that + * the network was not able to use STIR to verify the caller's number (i.e. nothing is + * known regarding the authenticity of the number. + * {@link Connection#VERIFICATION_STATUS_PASSED} indicates that the network was able to + * use STIR to verify the caller's number. This indicates that the network has a high + * degree of confidence that the incoming call actually originated from the indicated + * number. {@link Connection#VERIFICATION_STATUS_FAILED} indicates that the network's + * STIR verification did not pass. This indicates that the incoming call may not + * actually be from the indicated number. This could occur if, for example, the caller + * is using an impersonated phone number. + * <p> + * A {@link CallScreeningService} can use this information to help determine if an + * incoming call is potentially an unwanted call. A verification status of + * {@link Connection#VERIFICATION_STATUS_FAILED} indicates that an incoming call may not + * actually be from the number indicated on the call (i.e. impersonated number) and that it + * should potentially be blocked. Likewise, + * {@link Connection#VERIFICATION_STATUS_PASSED} can be used as a positive signal to + * help clarify that the incoming call is originating from the indicated number and it + * is less likely to be an undesirable call. + * <p> + * An {@link InCallService} can use this information to provide a visual indicator to the + * user regarding the verification status of a call and to help identify calls from + * potentially impersonated numbers. * @return the verification status. */ public @Connection.VerificationStatus int getCallerNumberVerificationStatus() { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 26b669a70cf8..e7af0534b7c9 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -10326,19 +10326,25 @@ public class TelephonyManager { * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}) * and {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. + * + * May return {@code null} when the subscription is inactive or when there was an error + * communicating with the phone process. */ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges @RequiresPermission(allOf = { Manifest.permission.READ_PHONE_STATE, Manifest.permission.ACCESS_COARSE_LOCATION }) - public ServiceState getServiceState() { + public @Nullable ServiceState getServiceState() { return getServiceStateForSubscriber(getSubId()); } /** * Returns the service state information on specified subscription. Callers require * either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information. + * + * May return {@code null} when the subscription is inactive or when there was an error + * communicating with the phone process. * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) @@ -10365,9 +10371,9 @@ public class TelephonyManager { * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the * voicemail ringtone. * @return The URI for the ringtone to play when receiving a voicemail from a specific - * PhoneAccount. + * PhoneAccount. May be {@code null} if no ringtone is set. */ - public Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) { + public @Nullable Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) { try { ITelephony service = getITelephony(); if (service != null) { diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index c895420157d7..85704d033634 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -213,7 +213,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { public void connect() { assertNotEquals("MockNetworkAgents can only be connected once", - getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED); + mNetworkInfo.getDetailedState(), NetworkInfo.DetailedState.CONNECTED); mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); mNetworkAgent.sendNetworkInfo(mNetworkInfo); } @@ -268,10 +268,6 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { return mNetworkAgent; } - public NetworkInfo getNetworkInfo() { - return mNetworkInfo; - } - public NetworkCapabilities getNetworkCapabilities() { return mNetworkCapabilities; } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 1df510987d25..daa2627d64cf 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -1155,7 +1155,7 @@ public class VpnTest { new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret, "name", profile.username, "password", profile.password, "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns", - "idle", "1800", "mtu", "1400", "mru", "1400" }, + "idle", "1800", "mtu", "1270", "mru", "1270" }, deps.mtpdArgs.get(10, TimeUnit.SECONDS)); // Now wait for the runner to be ready before testing for the route. legacyRunnerReady.block(10_000); diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java index 8f093779da11..6d2c7dc39ffd 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -150,7 +151,7 @@ public final class NetworkStatsSubscriptionsMonitorTest { } private void assertRatTypeChangedForSub(String subscriberId, int ratType) { - assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType); + assertEquals(ratType, mMonitor.getRatTypeForSubscriberId(subscriberId)); final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class); // Verify callback with the subscriberId and the RAT type should be as expected. // It will fail if get a callback with an unexpected RAT type. @@ -302,26 +303,84 @@ public final class NetworkStatsSubscriptionsMonitorTest { reset(mDelegate); // Set IMSI to null again to simulate somehow IMSI is not available, such as - // modem crash. Verify service should not unregister listener. + // modem crash. Verify service should unregister listener. updateSubscriberIdForTestSub(TEST_SUBID1, null); - verify(mTelephonyManager, never()).listen(any(), anyInt()); - assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); + verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()), + eq(PhoneStateListener.LISTEN_NONE)); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); reset(mDelegate); + clearInvocations(mTelephonyManager); - // Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI - // is not available. The monitor keeps the listener even if the IMSI disappears because - // the IMSI can never change for any given subId, therefore even if the IMSI is updated - // to null, the monitor should continue accepting updates of the RAT type. However, - // telephony is never actually supposed to do this, if the IMSI disappears there should - // not be updates, but it's still the right thing to do theoretically. - setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1, + // Simulate somehow IMSI is back. Verify service will register with + // another listener and fire callback accordingly. + final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 = + ArgumentCaptor.forClass(RatTypeListener.class); + updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + reset(mDelegate); + clearInvocations(mTelephonyManager); + + // Set RAT type of sim1 to LTE. Verify RAT type of sim1 still works. + setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1, TelephonyManager.NETWORK_TYPE_LTE); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE); reset(mDelegate); mMonitor.stop(); + verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor2.getValue()), + eq(PhoneStateListener.LISTEN_NONE)); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + } + + /** + * Verify that when IMSI suddenly changed for a given subId, the service will register a new + * listener and unregister the old one, and report changes on updated IMSI. This is for modem + * feature that may be enabled for certain carrier, which changes to use a different IMSI while + * roaming on certain networks for multi-IMSI SIM cards, but the subId stays the same. + */ + @Test + public void testSubscriberIdChanged() { + mMonitor.start(); + // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback + // before changing RAT type. + addTestSub(TEST_SUBID1, TEST_IMSI1); + final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor = + ArgumentCaptor.forClass(RatTypeListener.class); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + + // Set RAT type of sim1 to UMTS. + // Verify RAT type of sim1 changes accordingly. + setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1, + TelephonyManager.NETWORK_TYPE_UMTS); + assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS); + reset(mDelegate); + clearInvocations(mTelephonyManager); + + // Simulate IMSI of sim1 changed to IMSI2. Verify the service will register with + // another listener and remove the old one. The RAT type of new IMSI stays at + // NETWORK_TYPE_UNKNOWN until received initial callback from telephony. + final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 = + ArgumentCaptor.forClass(RatTypeListener.class); + updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI2); + verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(), + eq(PhoneStateListener.LISTEN_SERVICE_STATE)); verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()), eq(PhoneStateListener.LISTEN_NONE)); assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN); + reset(mDelegate); + + // Set RAT type of sim1 to UMTS for new listener to simulate the initial callback received + // from telephony after registration. Verify RAT type of sim1 changes with IMSI2 + // accordingly. + setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1, + TelephonyManager.NETWORK_TYPE_UMTS); + assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN); + assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UMTS); + reset(mDelegate); } } diff --git a/tests/vcn/OWNERS b/tests/vcn/OWNERS new file mode 100644 index 000000000000..33b9f0f75f81 --- /dev/null +++ b/tests/vcn/OWNERS @@ -0,0 +1,7 @@ +set noparent + +benedictwong@google.com +ckesting@google.com +evitayan@google.com +nharold@google.com +jchalard@google.com
\ No newline at end of file |