Loading src/java/com/android/internal/telephony/data/DataEvaluationResult.java 0 → 100644 +221 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.data; import android.annotation.CurrentTimeMillisLong; import android.annotation.NonNull; import java.text.DateFormat; import java.util.HashSet; import java.util.Set; /** * The class to describe the result of environment evaluation for whether allowing or disallowing * establishing a data network. */ public class DataEvaluationResult { /** Data disallowed reasons. There could be multiple reasons for not allowing data. */ private @NonNull Set<DataDisallowedReason> mDataDisallowedReasons = new HashSet<>(); /** Data allowed reason. It is intended to only have one allowed reason. */ private DataAllowedReason mDataAllowedReason = DataAllowedReason.NONE; /** The timestamp of evaluation time */ private @CurrentTimeMillisLong long mEvaluatedTime = 0; /** * Add a data disallowed reason. Note that adding a disallowed reason will clean up the * allowed reason because they are mutual exclusive. * * @param reason Disallowed reason. */ public void add(DataDisallowedReason reason) { mDataAllowedReason = DataAllowedReason.NONE; mDataDisallowedReasons.add(reason); mEvaluatedTime = System.currentTimeMillis(); } /** * Add a data allowed reason. Note that adding an allowed reason will clean up the disallowed * reasons because they are mutual exclusive. * * @param reason Allowed reason. */ public void add(DataAllowedReason reason) { mDataDisallowedReasons.clear(); // Only higher priority allowed reason can overwrite the old one. See // DataAllowedReason for the oder. if (reason.ordinal() > mDataAllowedReason.ordinal()) { mDataAllowedReason = reason; } mEvaluatedTime = System.currentTimeMillis(); } @Override public String toString() { StringBuilder reasonStr = new StringBuilder(); reasonStr.append("EvaluationResult: "); if (mDataDisallowedReasons.size() > 0) { reasonStr.append("Data disallowed reasons:"); for (DataDisallowedReason reason : mDataDisallowedReasons) { reasonStr.append(" ").append(reason); } } else { reasonStr.append("Data allowed reason:"); reasonStr.append(" ").append(mDataAllowedReason); } reasonStr.append(", time=" + DateFormat.getDateTimeInstance().format(mEvaluatedTime)); return reasonStr.toString(); } /** * @return {@code true} if data is allowed. */ public boolean isDataAllowed() { return mDataDisallowedReasons.size() == 0; } /** * Check if it contains a certain disallowed reason. * * @param reason The disallowed reason to check. * @return {@code true} if the provided reason matches one of the disallowed reasons. */ public boolean contains(DataDisallowedReason reason) { return mDataDisallowedReasons.contains(reason); } /** * Check if only one disallowed reason prevent data connection. * * @param reason The given reason to check * @return True if the given reason is the only one that prevents data connection */ public boolean containsOnly(DataDisallowedReason reason) { return mDataDisallowedReasons.size() == 1 && contains(reason); } /** * Check if the allowed reason is the specified reason. * * @param reason The allowed reason. * @return {@code true} if the specified reason matches the allowed reason. */ public boolean contains(DataAllowedReason reason) { return reason == mDataAllowedReason; } /** * @return {@code true} if the disallowed reasons contains hard reasons. */ public boolean containsHardDisallowedReasons() { for (DataDisallowedReason reason : mDataDisallowedReasons) { if (reason.isHardReason()) { return true; } } return false; } /** Disallowed reasons. There could be multiple reasons if data connection is not allowed. */ public enum DataDisallowedReason { // Soft failure reasons. A soft reason means that in certain conditions, data is still // allowed. Normally those reasons are due to users settings. /** Data is disabled by the user or policy. */ DATA_DISABLED(false), /** Data roaming is disabled by the user. */ ROAMING_DISABLED(false), /** Default data not selected. */ DEFAULT_DATA_UNSELECTED(false), // Belows are all hard failure reasons. A hard reason means no matter what the data should // not be allowed. /** Data registration state is not in service. */ NOT_IN_SERVICE(true), /** SIM is not ready. */ SIM_NOT_READY(true), /** Concurrent voice and data is not allowed. */ CONCURRENT_VOICE_DATA_NOT_ALLOWED(true), /** Carrier notified data should be restricted. */ DATA_RESTRICTED_BY_NETWORK(true), /** Radio power is off (i.e. airplane mode on) */ RADIO_POWER_OFF(true), /** Data disabled by telephony in some scenarios, for example, emergency call. */ INTERNAL_DATA_DISABLED(true), /** Airplane mode is forcibly turned on by the carrier. */ RADIO_DISABLED_BY_CARRIER(true), /** certain APNs are only allowed when the device is camped on NR. */ NOT_ON_NR(true), /** Data is not allowed while device is in emergency callback mode. */ IN_ECBM(true), /** Underlying data service is not bound. */ DATA_SERVICE_NOT_READY(true); private final boolean mIsHardReason; /** * @return {@code true} if the disallowed reason is a hard reason. */ public boolean isHardReason() { return mIsHardReason; } /** * Constructor * * @param isHardReason {@code true} if the disallowed reason is a hard reason. A hard reason * means no matter what the data should not be allowed. A soft reason means that in certain * conditions, data is still allowed. */ DataDisallowedReason(boolean isHardReason) { mIsHardReason = isHardReason; } } /** * Data allowed reasons. There will be only one reason if data is allowed. */ enum DataAllowedReason { // Note that unlike disallowed reasons, we only have one allowed reason every time // when we check data is allowed or not. The order of these allowed reasons is very // important. The lower ones take precedence over the upper ones. /** * None. This is the initial value. */ NONE, /** * The normal reason. This is the most common case. */ NORMAL, /** * The network brought up by this network request is unmetered. Should allowed no matter * the user enables or disables data. */ UNMETERED_USAGE, /** * The network request is restricted (i.e. Only privilege apps can access the network.) */ RESTRICTED_REQUEST, /** * Data is allowed because the network request is for emergency. This should be always at * the bottom (i.e. highest priority) */ EMERGENCY_REQUEST, } } src/java/com/android/internal/telephony/data/DataNetworkController.java +15 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.net.NetworkRequest; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RegistrantList; import android.os.SystemProperties; import android.telephony.AccessNetworkConstants; import android.telephony.data.DataProfile; Loading Loading @@ -145,6 +146,8 @@ public class DataNetworkController extends Handler { private final @NonNull NetworkRequestList mActivelyProcessedNetworkRequestList = new NetworkRequestList(); private final RegistrantList mInternetValidationStatusRegistrants = new RegistrantList(); /** * The sorted network request list by priority. The highest priority network request stays at * the head of the list. The highest priority is 100, the lowest is 0. Loading Loading @@ -215,7 +218,8 @@ public class DataNetworkController extends Handler { mDataConfigManager = new DataConfigManager(mPhone, looper); mDataSettingsManager = new DataSettingsManager(mPhone, looper); mDataProfileManager = new DataProfileManager(mPhone, looper); mDataStallMonitor = new DataStallMonitor(mPhone, looper); mDataStallMonitor = new DataStallMonitor(mPhone, this, mDataServiceManagers .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), looper); mDataTaskManager = new DataTaskManager(mPhone, looper); registerAllEvents(); Loading Loading @@ -406,6 +410,16 @@ public class DataNetworkController extends Handler { return mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_4); } /** * Register for internet data network validation status changed event. * * @param handler The handler to handle the event. * @param what The event. */ public void registerForInternetValidationStatusChanged(@NonNull Handler handler, int what) { mInternetValidationStatusRegistrants.addUnique(handler, what, null); } /** * Log debug messages. * @param s debug messages Loading src/java/com/android/internal/telephony/data/DataStallMonitor.java +55 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.internal.telephony.data; import android.annotation.NonNull; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading @@ -34,25 +35,75 @@ import java.io.PrintWriter; * actions to recover */ public class DataStallMonitor extends Handler { private final Phone mPhone; private final String mLogTag; private final LocalLog mLocalLog = new LocalLog(128); /** Event for data config updated. */ private static final int EVENT_DATA_CONFIG_UPDATED = 1; /** Event for internet validation status changed. */ private static final int EVENT_INTERNET_VALIDATION_STATUS_CHANGED = 2; private final @NonNull Phone mPhone; private final @NonNull String mLogTag; private final @NonNull LocalLog mLocalLog = new LocalLog(128); /** Data network controller */ private final @NonNull DataNetworkController mDataNetworkController; /** Data config manager */ private final @NonNull DataConfigManager mDataConfigManager; /** Cellular data service */ private final @NonNull DataServiceManager mWwanDataServiceManager; /** * Constructor * * @param phone The phone instance. * @param dataServiceManager The WWAN data service manager. * @param looper The looper to be used by the handler. Currently the handler thread is the * phone process's main thread. */ public DataStallMonitor(Phone phone, Looper looper) { public DataStallMonitor(@NonNull Phone phone, @NonNull DataNetworkController dataNetworkController, @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper) { super(looper); mPhone = phone; mLogTag = "DSTMTR-" + mPhone.getPhoneId(); mDataNetworkController = dataNetworkController; mWwanDataServiceManager = dataServiceManager; mDataConfigManager = mDataNetworkController.getDataConfigManager(); mDataConfigManager.registerForConfigUpdate(this, EVENT_DATA_CONFIG_UPDATED); mDataNetworkController.registerForInternetValidationStatusChanged(this, EVENT_INTERNET_VALIDATION_STATUS_CHANGED); } @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_DATA_CONFIG_UPDATED: onDataConfigUpdated(); break; case EVENT_INTERNET_VALIDATION_STATUS_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; Boolean isValid = (Boolean) ar.result; onInternetValidationStatusChanged(isValid); break; } } /** * Called when data config was updated. */ private void onDataConfigUpdated() { } /** * Called when internet validation status changed. * * @param isValid {@code true} if internet validation succeeded. */ private void onInternetValidationStatusChanged(boolean isValid) { } Loading src/java/com/android/internal/telephony/data/DataUtils.java +3 −2 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ public class DataUtils { * @param netCap Network capability. * @return Network capability in string format. */ public static String networkCapabilityToString(int netCap) { public static @NonNull String networkCapabilityToString(int netCap) { switch (netCap) { case NetworkCapabilities.NET_CAPABILITY_MMS: return "MMS"; case NetworkCapabilities.NET_CAPABILITY_SUPL: return "SUPL"; Loading Loading @@ -111,7 +111,8 @@ public class DataUtils { * @param netCaps Network capabilities. * @return Network capabilities in string format. */ public static String networkCapabilitiesToString(int[] netCaps) { public static @NonNull String networkCapabilitiesToString(int[] netCaps) { if (netCaps == null) return ""; return Arrays.stream(netCaps) .mapToObj(DataUtils::networkCapabilityToString) .collect(Collectors.joining("|")); Loading Loading
src/java/com/android/internal/telephony/data/DataEvaluationResult.java 0 → 100644 +221 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.telephony.data; import android.annotation.CurrentTimeMillisLong; import android.annotation.NonNull; import java.text.DateFormat; import java.util.HashSet; import java.util.Set; /** * The class to describe the result of environment evaluation for whether allowing or disallowing * establishing a data network. */ public class DataEvaluationResult { /** Data disallowed reasons. There could be multiple reasons for not allowing data. */ private @NonNull Set<DataDisallowedReason> mDataDisallowedReasons = new HashSet<>(); /** Data allowed reason. It is intended to only have one allowed reason. */ private DataAllowedReason mDataAllowedReason = DataAllowedReason.NONE; /** The timestamp of evaluation time */ private @CurrentTimeMillisLong long mEvaluatedTime = 0; /** * Add a data disallowed reason. Note that adding a disallowed reason will clean up the * allowed reason because they are mutual exclusive. * * @param reason Disallowed reason. */ public void add(DataDisallowedReason reason) { mDataAllowedReason = DataAllowedReason.NONE; mDataDisallowedReasons.add(reason); mEvaluatedTime = System.currentTimeMillis(); } /** * Add a data allowed reason. Note that adding an allowed reason will clean up the disallowed * reasons because they are mutual exclusive. * * @param reason Allowed reason. */ public void add(DataAllowedReason reason) { mDataDisallowedReasons.clear(); // Only higher priority allowed reason can overwrite the old one. See // DataAllowedReason for the oder. if (reason.ordinal() > mDataAllowedReason.ordinal()) { mDataAllowedReason = reason; } mEvaluatedTime = System.currentTimeMillis(); } @Override public String toString() { StringBuilder reasonStr = new StringBuilder(); reasonStr.append("EvaluationResult: "); if (mDataDisallowedReasons.size() > 0) { reasonStr.append("Data disallowed reasons:"); for (DataDisallowedReason reason : mDataDisallowedReasons) { reasonStr.append(" ").append(reason); } } else { reasonStr.append("Data allowed reason:"); reasonStr.append(" ").append(mDataAllowedReason); } reasonStr.append(", time=" + DateFormat.getDateTimeInstance().format(mEvaluatedTime)); return reasonStr.toString(); } /** * @return {@code true} if data is allowed. */ public boolean isDataAllowed() { return mDataDisallowedReasons.size() == 0; } /** * Check if it contains a certain disallowed reason. * * @param reason The disallowed reason to check. * @return {@code true} if the provided reason matches one of the disallowed reasons. */ public boolean contains(DataDisallowedReason reason) { return mDataDisallowedReasons.contains(reason); } /** * Check if only one disallowed reason prevent data connection. * * @param reason The given reason to check * @return True if the given reason is the only one that prevents data connection */ public boolean containsOnly(DataDisallowedReason reason) { return mDataDisallowedReasons.size() == 1 && contains(reason); } /** * Check if the allowed reason is the specified reason. * * @param reason The allowed reason. * @return {@code true} if the specified reason matches the allowed reason. */ public boolean contains(DataAllowedReason reason) { return reason == mDataAllowedReason; } /** * @return {@code true} if the disallowed reasons contains hard reasons. */ public boolean containsHardDisallowedReasons() { for (DataDisallowedReason reason : mDataDisallowedReasons) { if (reason.isHardReason()) { return true; } } return false; } /** Disallowed reasons. There could be multiple reasons if data connection is not allowed. */ public enum DataDisallowedReason { // Soft failure reasons. A soft reason means that in certain conditions, data is still // allowed. Normally those reasons are due to users settings. /** Data is disabled by the user or policy. */ DATA_DISABLED(false), /** Data roaming is disabled by the user. */ ROAMING_DISABLED(false), /** Default data not selected. */ DEFAULT_DATA_UNSELECTED(false), // Belows are all hard failure reasons. A hard reason means no matter what the data should // not be allowed. /** Data registration state is not in service. */ NOT_IN_SERVICE(true), /** SIM is not ready. */ SIM_NOT_READY(true), /** Concurrent voice and data is not allowed. */ CONCURRENT_VOICE_DATA_NOT_ALLOWED(true), /** Carrier notified data should be restricted. */ DATA_RESTRICTED_BY_NETWORK(true), /** Radio power is off (i.e. airplane mode on) */ RADIO_POWER_OFF(true), /** Data disabled by telephony in some scenarios, for example, emergency call. */ INTERNAL_DATA_DISABLED(true), /** Airplane mode is forcibly turned on by the carrier. */ RADIO_DISABLED_BY_CARRIER(true), /** certain APNs are only allowed when the device is camped on NR. */ NOT_ON_NR(true), /** Data is not allowed while device is in emergency callback mode. */ IN_ECBM(true), /** Underlying data service is not bound. */ DATA_SERVICE_NOT_READY(true); private final boolean mIsHardReason; /** * @return {@code true} if the disallowed reason is a hard reason. */ public boolean isHardReason() { return mIsHardReason; } /** * Constructor * * @param isHardReason {@code true} if the disallowed reason is a hard reason. A hard reason * means no matter what the data should not be allowed. A soft reason means that in certain * conditions, data is still allowed. */ DataDisallowedReason(boolean isHardReason) { mIsHardReason = isHardReason; } } /** * Data allowed reasons. There will be only one reason if data is allowed. */ enum DataAllowedReason { // Note that unlike disallowed reasons, we only have one allowed reason every time // when we check data is allowed or not. The order of these allowed reasons is very // important. The lower ones take precedence over the upper ones. /** * None. This is the initial value. */ NONE, /** * The normal reason. This is the most common case. */ NORMAL, /** * The network brought up by this network request is unmetered. Should allowed no matter * the user enables or disables data. */ UNMETERED_USAGE, /** * The network request is restricted (i.e. Only privilege apps can access the network.) */ RESTRICTED_REQUEST, /** * Data is allowed because the network request is for emergency. This should be always at * the bottom (i.e. highest priority) */ EMERGENCY_REQUEST, } }
src/java/com/android/internal/telephony/data/DataNetworkController.java +15 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.net.NetworkRequest; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RegistrantList; import android.os.SystemProperties; import android.telephony.AccessNetworkConstants; import android.telephony.data.DataProfile; Loading Loading @@ -145,6 +146,8 @@ public class DataNetworkController extends Handler { private final @NonNull NetworkRequestList mActivelyProcessedNetworkRequestList = new NetworkRequestList(); private final RegistrantList mInternetValidationStatusRegistrants = new RegistrantList(); /** * The sorted network request list by priority. The highest priority network request stays at * the head of the list. The highest priority is 100, the lowest is 0. Loading Loading @@ -215,7 +218,8 @@ public class DataNetworkController extends Handler { mDataConfigManager = new DataConfigManager(mPhone, looper); mDataSettingsManager = new DataSettingsManager(mPhone, looper); mDataProfileManager = new DataProfileManager(mPhone, looper); mDataStallMonitor = new DataStallMonitor(mPhone, looper); mDataStallMonitor = new DataStallMonitor(mPhone, this, mDataServiceManagers .get(AccessNetworkConstants.TRANSPORT_TYPE_WWAN), looper); mDataTaskManager = new DataTaskManager(mPhone, looper); registerAllEvents(); Loading Loading @@ -406,6 +410,16 @@ public class DataNetworkController extends Handler { return mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_4); } /** * Register for internet data network validation status changed event. * * @param handler The handler to handle the event. * @param what The event. */ public void registerForInternetValidationStatusChanged(@NonNull Handler handler, int what) { mInternetValidationStatusRegistrants.addUnique(handler, what, null); } /** * Log debug messages. * @param s debug messages Loading
src/java/com/android/internal/telephony/data/DataStallMonitor.java +55 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.internal.telephony.data; import android.annotation.NonNull; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading @@ -34,25 +35,75 @@ import java.io.PrintWriter; * actions to recover */ public class DataStallMonitor extends Handler { private final Phone mPhone; private final String mLogTag; private final LocalLog mLocalLog = new LocalLog(128); /** Event for data config updated. */ private static final int EVENT_DATA_CONFIG_UPDATED = 1; /** Event for internet validation status changed. */ private static final int EVENT_INTERNET_VALIDATION_STATUS_CHANGED = 2; private final @NonNull Phone mPhone; private final @NonNull String mLogTag; private final @NonNull LocalLog mLocalLog = new LocalLog(128); /** Data network controller */ private final @NonNull DataNetworkController mDataNetworkController; /** Data config manager */ private final @NonNull DataConfigManager mDataConfigManager; /** Cellular data service */ private final @NonNull DataServiceManager mWwanDataServiceManager; /** * Constructor * * @param phone The phone instance. * @param dataServiceManager The WWAN data service manager. * @param looper The looper to be used by the handler. Currently the handler thread is the * phone process's main thread. */ public DataStallMonitor(Phone phone, Looper looper) { public DataStallMonitor(@NonNull Phone phone, @NonNull DataNetworkController dataNetworkController, @NonNull DataServiceManager dataServiceManager, @NonNull Looper looper) { super(looper); mPhone = phone; mLogTag = "DSTMTR-" + mPhone.getPhoneId(); mDataNetworkController = dataNetworkController; mWwanDataServiceManager = dataServiceManager; mDataConfigManager = mDataNetworkController.getDataConfigManager(); mDataConfigManager.registerForConfigUpdate(this, EVENT_DATA_CONFIG_UPDATED); mDataNetworkController.registerForInternetValidationStatusChanged(this, EVENT_INTERNET_VALIDATION_STATUS_CHANGED); } @Override public void handleMessage(Message msg) { switch (msg.what) { case EVENT_DATA_CONFIG_UPDATED: onDataConfigUpdated(); break; case EVENT_INTERNET_VALIDATION_STATUS_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; Boolean isValid = (Boolean) ar.result; onInternetValidationStatusChanged(isValid); break; } } /** * Called when data config was updated. */ private void onDataConfigUpdated() { } /** * Called when internet validation status changed. * * @param isValid {@code true} if internet validation succeeded. */ private void onInternetValidationStatusChanged(boolean isValid) { } Loading
src/java/com/android/internal/telephony/data/DataUtils.java +3 −2 Original line number Diff line number Diff line Loading @@ -61,7 +61,7 @@ public class DataUtils { * @param netCap Network capability. * @return Network capability in string format. */ public static String networkCapabilityToString(int netCap) { public static @NonNull String networkCapabilityToString(int netCap) { switch (netCap) { case NetworkCapabilities.NET_CAPABILITY_MMS: return "MMS"; case NetworkCapabilities.NET_CAPABILITY_SUPL: return "SUPL"; Loading Loading @@ -111,7 +111,8 @@ public class DataUtils { * @param netCaps Network capabilities. * @return Network capabilities in string format. */ public static String networkCapabilitiesToString(int[] netCaps) { public static @NonNull String networkCapabilitiesToString(int[] netCaps) { if (netCaps == null) return ""; return Arrays.stream(netCaps) .mapToObj(DataUtils::networkCapabilityToString) .collect(Collectors.joining("|")); Loading