diff options
15 files changed, 227 insertions, 449 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2979cd8a5dba..7a1d85c93de0 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1720,14 +1720,8 @@ public class ConnectivityManager { // ignored } - /** - * Return quota status for the current active network, or {@code null} if no - * network is active. Quota status can change rapidly, so these values - * shouldn't be cached. - * - * @hide - */ - @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + /** {@hide} */ + @Deprecated public NetworkQuotaInfo getActiveNetworkQuotaInfo() { try { return mService.getActiveNetworkQuotaInfo(); diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 63bbd96bd01d..7b1e61e6dea1 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -63,9 +63,9 @@ interface INetworkPolicyManager { int getRestrictBackgroundByCaller(); void setDeviceIdleMode(boolean enabled); + void setWifiMeteredOverride(String networkId, int meteredOverride); NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state); - boolean isNetworkMetered(in NetworkState state); void factoryReset(String subscriber); } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 84c32bec8ef7..818aa211625d 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -16,8 +16,8 @@ package android.net; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; @@ -121,7 +121,6 @@ public class NetworkInfo implements Parcelable { private boolean mIsFailover; private boolean mIsAvailable; private boolean mIsRoaming; - private boolean mIsMetered; /** * @hide @@ -154,7 +153,6 @@ public class NetworkInfo implements Parcelable { mIsFailover = source.mIsFailover; mIsAvailable = source.mIsAvailable; mIsRoaming = source.mIsRoaming; - mIsMetered = source.mIsMetered; } } } @@ -327,31 +325,6 @@ public class NetworkInfo implements Parcelable { } /** - * Returns if this network is metered. A network is classified as metered - * when the user is sensitive to heavy data usage on that connection due to - * monetary costs, data limitations or battery/performance issues. You - * should check this before doing large data transfers, and warn the user or - * delay the operation until another network is available. - * - * @return {@code true} if large transfers should be avoided, otherwise - * {@code false}. - * @hide - */ - public boolean isMetered() { - synchronized (this) { - return mIsMetered; - } - } - - /** {@hide} */ - @VisibleForTesting - public void setMetered(boolean isMetered) { - synchronized (this) { - mIsMetered = isMetered; - } - } - - /** * Reports the current coarse-grained state of the network. * @return the coarse-grained state */ @@ -434,7 +407,6 @@ public class NetworkInfo implements Parcelable { append(", failover: ").append(mIsFailover). append(", available: ").append(mIsAvailable). append(", roaming: ").append(mIsRoaming). - append(", metered: ").append(mIsMetered). append("]"); return builder.toString(); } @@ -457,7 +429,6 @@ public class NetworkInfo implements Parcelable { dest.writeInt(mIsFailover ? 1 : 0); dest.writeInt(mIsAvailable ? 1 : 0); dest.writeInt(mIsRoaming ? 1 : 0); - dest.writeInt(mIsMetered ? 1 : 0); dest.writeString(mReason); dest.writeString(mExtraInfo); } @@ -476,7 +447,6 @@ public class NetworkInfo implements Parcelable { netInfo.mIsFailover = in.readInt() != 0; netInfo.mIsAvailable = in.readInt() != 0; netInfo.mIsRoaming = in.readInt() != 0; - netInfo.mIsMetered = in.readInt() != 0; netInfo.mReason = in.readString(); netInfo.mExtraInfo = in.readString(); return netInfo; diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index 9870e7b6fa0c..58306675d2c7 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -52,7 +52,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> { public long limitBytes; public long lastWarningSnooze; public long lastLimitSnooze; - public boolean metered; + @Deprecated public boolean metered; public boolean inferred; private static final long DEFAULT_MTU = 1500; diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 4d94a55cd0c4..fc96004e7dcb 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -26,6 +26,8 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiInfo; import android.os.RemoteException; import android.os.UserHandle; import android.util.DebugUtils; @@ -400,4 +402,13 @@ public class NetworkPolicyManager { public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) { return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; } + + public static String resolveNetworkId(WifiConfiguration config) { + return WifiInfo.removeDoubleQuotes(config.isPasspoint() + ? config.providerFriendlyName : config.SSID); + } + + public static String resolveNetworkId(String ssid) { + return WifiInfo.removeDoubleQuotes(ssid); + } } diff --git a/core/java/android/net/NetworkQuotaInfo.java b/core/java/android/net/NetworkQuotaInfo.java index 1725ed7b015e..b95f1d983180 100644 --- a/core/java/android/net/NetworkQuotaInfo.java +++ b/core/java/android/net/NetworkQuotaInfo.java @@ -20,41 +20,32 @@ import android.os.Parcel; import android.os.Parcelable; /** - * Information about quota status on a specific network. - * + * @deprecated nobody should be using this, but keep it around returning stub + * values to prevent app crashes. * @hide */ +@Deprecated public class NetworkQuotaInfo implements Parcelable { - private final long mEstimatedBytes; - private final long mSoftLimitBytes; - private final long mHardLimitBytes; - public static final long NO_LIMIT = -1; /** {@hide} */ - public NetworkQuotaInfo(long estimatedBytes, long softLimitBytes, long hardLimitBytes) { - mEstimatedBytes = estimatedBytes; - mSoftLimitBytes = softLimitBytes; - mHardLimitBytes = hardLimitBytes; + public NetworkQuotaInfo() { } /** {@hide} */ public NetworkQuotaInfo(Parcel in) { - mEstimatedBytes = in.readLong(); - mSoftLimitBytes = in.readLong(); - mHardLimitBytes = in.readLong(); } public long getEstimatedBytes() { - return mEstimatedBytes; + return 0; } public long getSoftLimitBytes() { - return mSoftLimitBytes; + return NO_LIMIT; } public long getHardLimitBytes() { - return mHardLimitBytes; + return NO_LIMIT; } @Override @@ -64,9 +55,6 @@ public class NetworkQuotaInfo implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { - out.writeLong(mEstimatedBytes); - out.writeLong(mSoftLimitBytes); - out.writeLong(mHardLimitBytes); } public static final Creator<NetworkQuotaInfo> CREATOR = new Creator<NetworkQuotaInfo>() { diff --git a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java index 2e77f4264de6..3640bfa4b23a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java +++ b/packages/SettingsLib/src/com/android/settingslib/NetworkPolicyEditor.java @@ -21,6 +21,7 @@ import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkTemplate.MATCH_WIFI; + import static com.android.internal.util.Preconditions.checkNotNull; import android.net.NetworkPolicy; @@ -204,53 +205,6 @@ public class NetworkPolicyEditor { writeAsync(); } - public boolean getPolicyMetered(NetworkTemplate template) { - NetworkPolicy policy = getPolicy(template); - if (policy != null) { - return policy.metered; - } else { - return false; - } - } - - public void setPolicyMetered(NetworkTemplate template, boolean metered) { - boolean modified = false; - - NetworkPolicy policy = getPolicy(template); - if (metered) { - if (policy == null) { - policy = buildDefaultPolicy(template); - policy.metered = true; - policy.inferred = false; - mPolicies.add(policy); - modified = true; - } else if (!policy.metered) { - policy.metered = true; - policy.inferred = false; - modified = true; - } - - } else { - if (policy == null) { - // ignore when policy doesn't exist - } else if (policy.metered) { - policy.metered = false; - policy.inferred = false; - modified = true; - } - } - - // Remove legacy unquoted policies while we're here - final NetworkTemplate unquoted = buildUnquotedNetworkTemplate(template); - final NetworkPolicy unquotedPolicy = getPolicy(unquoted); - if (unquotedPolicy != null) { - mPolicies.remove(unquotedPolicy); - modified = true; - } - - if (modified) writeAsync(); - } - /** * Build a revised {@link NetworkTemplate} that matches the same rule, but * with an unquoted {@link NetworkTemplate#getNetworkId()}. Used to work diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index ec4141518f82..7bbc598a0a0e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -552,15 +552,11 @@ public class AccessPoint implements Comparable<AccessPoint> { } /** - * Returns if the network is marked metered. Metering can be marked through its config in - * {@link WifiConfiguration}, after connection in {@link WifiInfo}, or from a score config in - * {@link ScoredNetwork}. + * Returns if the network should be considered metered. */ public boolean isMetered() { return mIsScoredNetworkMetered - || (mConfig != null && mConfig.meteredHint) - || (mInfo != null && mInfo.getMeteredHint() - || (mNetworkInfo != null && mNetworkInfo.isMetered())); + || WifiConfiguration.isMetered(mConfig, mInfo); } public NetworkInfo getNetworkInfo() { diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index c08dd6ed97cd..aed027002939 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -298,23 +298,6 @@ public class AccessPointTest { } @Test - public void testIsMetered_returnTrueWhenNetworkInfoIsMetered() { - WifiConfiguration configuration = createWifiConfiguration(); - - NetworkInfo networkInfo = - new NetworkInfo(ConnectivityManager.TYPE_WIFI, 2, "WIFI", "WIFI_SUBTYPE"); - networkInfo.setMetered(true); - AccessPoint accessPoint = new AccessPoint(mContext, configuration); - WifiInfo wifiInfo = new WifiInfo(); - wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(configuration.SSID)); - wifiInfo.setBSSID(configuration.BSSID); - wifiInfo.setNetworkId(configuration.networkId); - accessPoint.update(configuration, wifiInfo, networkInfo); - - assertThat(accessPoint.isMetered()).isTrue(); - } - - @Test public void testIsMetered_returnTrueWhenScoredNetworkIsMetered() { AccessPoint ap = createAccessPointWithScanResultCache(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index a2e74b6a3812..8200289a76b2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1036,8 +1036,7 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Apply any relevant filters to {@link NetworkState} for the given UID. For * example, this may mark the network as {@link DetailedState#BLOCKED} based - * on {@link #isNetworkWithLinkPropertiesBlocked}, or - * {@link NetworkInfo#isMetered()} based on network policies. + * on {@link #isNetworkWithLinkPropertiesBlocked}. */ private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) { if (state == null || state.networkInfo == null || state.linkProperties == null) return; @@ -1048,15 +1047,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (mLockdownTracker != null) { mLockdownTracker.augmentNetworkInfo(state.networkInfo); } - - // TODO: apply metered state closer to NetworkAgentInfo - final long token = Binder.clearCallingIdentity(); - try { - state.networkInfo.setMetered(mPolicyManager.isNetworkMetered(state)); - } catch (RemoteException e) { - } finally { - Binder.restoreCallingIdentity(token); - } } /** @@ -1326,30 +1316,24 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override + @Deprecated public NetworkQuotaInfo getActiveNetworkQuotaInfo() { - enforceAccessPermission(); - final int uid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - final NetworkState state = getUnfilteredActiveNetworkState(uid); - if (state.networkInfo != null) { - try { - return mPolicyManager.getNetworkQuotaInfo(state); - } catch (RemoteException e) { - } - } - return null; - } finally { - Binder.restoreCallingIdentity(token); - } + Log.w(TAG, "Shame on UID " + Binder.getCallingUid() + + " for calling the hidden API getNetworkQuotaInfo(). Shame!"); + return new NetworkQuotaInfo(); } @Override public boolean isActiveNetworkMetered() { enforceAccessPermission(); - final NetworkInfo info = getActiveNetworkInfo(); - return (info != null) ? info.isMetered() : false; + final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork()); + if (caps != null) { + return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } else { + // Always return the most conservative value + return true; + } } private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() { @@ -2759,7 +2743,8 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceAccessPermission(); NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); - if (nai != null && !nai.networkInfo.isMetered()) { + if (nai != null && nai.networkCapabilities + .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) { return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED; } diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index 17c89282f280..78367fe97a54 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -85,7 +85,7 @@ public final class ConnectivityController extends StateController implements @Override public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) { if (jobStatus.hasConnectivityConstraint()) { - updateConstraintsSatisfied(jobStatus, null); + updateConstraintsSatisfied(jobStatus); mTrackedJobs.add(jobStatus); jobStatus.setTrackingController(JobStatus.TRACKING_CONNECTIVITY); } @@ -99,23 +99,25 @@ public final class ConnectivityController extends StateController implements } } - private boolean updateConstraintsSatisfied(JobStatus jobStatus, - NetworkCapabilities capabilities) { + private boolean updateConstraintsSatisfied(JobStatus jobStatus) { final int jobUid = jobStatus.getSourceUid(); final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0; final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobUid, ignoreBlocked); - if (capabilities == null) { - final Network network = mConnManager.getActiveNetworkForUid(jobUid, ignoreBlocked); - capabilities = mConnManager.getNetworkCapabilities(network); - } + final Network network = mConnManager.getActiveNetworkForUid(jobUid, ignoreBlocked); + final NetworkCapabilities capabilities = (network != null) + ? mConnManager.getNetworkCapabilities(network) : null; - final boolean validated = capabilities != null + final boolean validated = (capabilities != null) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); - final boolean connected = info != null && info.isConnected(); + final boolean connected = (info != null) && info.isConnected(); final boolean connectionUsable = connected && validated; - final boolean metered = connected && info.isMetered(); - final boolean unmetered = connected && !info.isMetered(); - final boolean notRoaming = connected && !info.isRoaming(); + + final boolean metered = connected && (capabilities != null) + && !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + final boolean unmetered = connected && (capabilities != null) + && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + final boolean notRoaming = connected && (info != null) + && !info.isRoaming(); boolean changed = false; changed |= jobStatus.setConnectivityConstraintSatisfied(connectionUsable); @@ -148,13 +150,13 @@ public final class ConnectivityController extends StateController implements * @param uid only update jobs belonging to this UID, or {@code -1} to * update all tracked jobs. */ - private void updateTrackedJobs(int uid, NetworkCapabilities capabilities) { + private void updateTrackedJobs(int uid) { synchronized (mLock) { boolean changed = false; for (int i = mTrackedJobs.size()-1; i >= 0; i--) { final JobStatus js = mTrackedJobs.valueAt(i); if (uid == -1 || uid == js.getSourceUid()) { - changed |= updateConstraintsSatisfied(js, capabilities); + changed |= updateConstraintsSatisfied(js); } } if (changed) { @@ -187,7 +189,7 @@ public final class ConnectivityController extends StateController implements if (DEBUG) { Slog.v(TAG, "onCapabilitiesChanged() : " + networkCapabilities); } - updateTrackedJobs(-1, networkCapabilities); + updateTrackedJobs(-1); } @Override @@ -195,7 +197,7 @@ public final class ConnectivityController extends StateController implements if (DEBUG) { Slog.v(TAG, "Network lost"); } - updateTrackedJobs(-1, null); + updateTrackedJobs(-1); } }; @@ -205,7 +207,7 @@ public final class ConnectivityController extends StateController implements if (DEBUG) { Slog.v(TAG, "Uid rules changed for " + uid); } - updateTrackedJobs(uid, null); + updateTrackedJobs(uid); } @Override @@ -218,7 +220,7 @@ public final class ConnectivityController extends StateController implements if (DEBUG) { Slog.v(TAG, "Background restriction change to " + restrictBackground); } - updateTrackedJobs(-1, null); + updateTrackedJobs(-1); } @Override @@ -226,7 +228,7 @@ public final class ConnectivityController extends StateController implements if (DEBUG) { Slog.v(TAG, "Uid policy changed for " + uid); } - updateTrackedJobs(uid, null); + updateTrackedJobs(uid); } }; diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index b6af07677d61..8b8811e252c0 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -18,7 +18,6 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; -import static android.Manifest.permission.DUMP; import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.READ_PHONE_STATE; @@ -33,9 +32,6 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED; import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_WIMAX; -import static android.net.ConnectivityManager.isNetworkTypeMobile; -import static android.net.NetworkPolicy.CYCLE_NONE; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; import static android.net.NetworkPolicy.WARNING_DISABLED; @@ -46,13 +42,13 @@ import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY; import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY; +import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS; +import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS; import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED; -import static android.net.NetworkPolicyManager.MASK_METERED_NETWORKS; -import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS; import static android.net.NetworkPolicyManager.RULE_NONE; import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; @@ -60,6 +56,7 @@ import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED; import static android.net.NetworkPolicyManager.computeLastCycleBoundary; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode; import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground; +import static android.net.NetworkPolicyManager.resolveNetworkId; import static android.net.NetworkPolicyManager.uidPoliciesToString; import static android.net.NetworkPolicyManager.uidRulesToString; import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER; @@ -68,16 +65,9 @@ import static android.net.NetworkTemplate.MATCH_MOBILE_ALL; import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.TrafficStats.MB_IN_BYTES; -import static android.net.wifi.WifiManager.CHANGE_REASON_ADDED; -import static android.net.wifi.WifiManager.CHANGE_REASON_REMOVED; -import static android.net.wifi.WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION; -import static android.net.wifi.WifiManager.EXTRA_CHANGE_REASON; -import static android.net.wifi.WifiManager.EXTRA_NETWORK_INFO; -import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION; -import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO; import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED; -import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT; import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED; +import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static com.android.internal.util.ArrayUtils.appendInt; @@ -127,15 +117,12 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkProperties; import android.net.NetworkIdentity; -import android.net.NetworkInfo; import android.net.NetworkPolicy; import android.net.NetworkQuotaInfo; import android.net.NetworkState; import android.net.NetworkTemplate; import android.net.wifi.WifiConfiguration; -import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.os.PowerSaveState; import android.os.Binder; import android.os.Environment; import android.os.Handler; @@ -147,6 +134,7 @@ import android.os.MessageQueue.IdleHandler; import android.os.PersistableBundle; import android.os.PowerManager; import android.os.PowerManagerInternal; +import android.os.PowerSaveState; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; @@ -190,8 +178,8 @@ import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemConfig; - import com.android.server.power.BatterySaverPolicy.ServiceType; + import libcore.io.IoUtils; import com.google.android.collect.Lists; @@ -212,8 +200,8 @@ import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Calendar; +import java.util.List; import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -756,15 +744,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mContext.registerReceiver(mSnoozeWarningReceiver, snoozeWarningFilter, MANAGE_NETWORK_POLICY, mHandler); - // listen for configured wifi networks to be removed - final IntentFilter wifiConfigFilter = - new IntentFilter(CONFIGURED_NETWORKS_CHANGED_ACTION); - mContext.registerReceiver(mWifiConfigReceiver, wifiConfigFilter, null, mHandler); - - // listen for wifi state changes to catch metered hint - final IntentFilter wifiStateFilter = new IntentFilter( - WifiManager.NETWORK_STATE_CHANGED_ACTION); - mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler); + // listen for configured wifi networks to be loaded + final IntentFilter wifiFilter = + new IntentFilter(WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION); + mContext.registerReceiver(mWifiReceiver, wifiFilter, null, mHandler); // listen for carrier config changes to update data cycle information final IntentFilter carrierConfigFilter = new IntentFilter( @@ -960,80 +943,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { }; /** - * Receiver that watches for {@link WifiConfiguration} to be changed. - */ - final private BroadcastReceiver mWifiConfigReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // on background handler thread, and verified CONNECTIVITY_INTERNAL - // permission above. - - final int reason = intent.getIntExtra(EXTRA_CHANGE_REASON, CHANGE_REASON_ADDED); - if (reason == CHANGE_REASON_REMOVED) { - final WifiConfiguration config = intent.getParcelableExtra( - EXTRA_WIFI_CONFIGURATION); - if (config.SSID != null) { - final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(config.SSID); - synchronized (mUidRulesFirstLock) { - synchronized (mNetworkPoliciesSecondLock) { - if (mNetworkPolicy.containsKey(template)) { - mNetworkPolicy.remove(template); - writePolicyAL(); - } - } - } - } - } - } - }; - - /** - * Receiver that watches {@link WifiInfo} state changes to infer metered - * state. Ignores hints when policy is user-defined. + * Receiver that watches for {@link WifiConfiguration} to be loaded so that + * we can perform upgrade logic. */ - final private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mWifiReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - // on background handler thread, and verified CONNECTIVITY_INTERNAL - // permission above. - - // ignore when not connected - final NetworkInfo netInfo = intent.getParcelableExtra(EXTRA_NETWORK_INFO); - if (!netInfo.isConnected()) return; - - final WifiInfo info = intent.getParcelableExtra(EXTRA_WIFI_INFO); - final boolean meteredHint = info.getMeteredHint(); - - final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(info.getSSID()); synchronized (mUidRulesFirstLock) { synchronized (mNetworkPoliciesSecondLock) { - NetworkPolicy policy = mNetworkPolicy.get(template); - if (policy == null && meteredHint) { - // policy doesn't exist, and AP is hinting that it's - // metered: create an inferred policy. - policy = newWifiPolicy(template, meteredHint); - addNetworkPolicyAL(policy); - - } else if (policy != null && policy.inferred) { - // policy exists, and was inferred: update its current - // metered state. - policy.metered = meteredHint; - - // since this is inferred for each wifi session, just update - // rules without persisting. - updateNetworkRulesNL(); - } + upgradeWifiMeteredOverrideAL(); } } + // Only need to perform upgrade logic once + mContext.unregisterReceiver(this); } }; - static NetworkPolicy newWifiPolicy(NetworkTemplate template, boolean metered) { - return new NetworkPolicy(template, CYCLE_NONE, Time.TIMEZONE_UTC, - WARNING_DISABLED, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, - metered, true); - } - /** * Observer that watches for {@link INetworkManagementService} alerts. */ @@ -1905,7 +1830,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { cycleTimezone, warningBytes, limitBytes, lastWarningSnooze, lastLimitSnooze, metered, inferred)); } - } else if (TAG_UID_POLICY.equals(tag)) { final int uid = readIntAttribute(in, ATTR_UID); final int policy = readIntAttribute(in, ATTR_POLICY); @@ -1991,6 +1915,40 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + /** + * Perform upgrade step of moving any user-defined meterness overrides over + * into {@link WifiConfiguration}. + */ + private void upgradeWifiMeteredOverrideAL() { + boolean modified = false; + final WifiManager wm = mContext.getSystemService(WifiManager.class); + final List<WifiConfiguration> configs = wm.getConfiguredNetworks(); + for (int i = 0; i < mNetworkPolicy.size(); ) { + final NetworkPolicy policy = mNetworkPolicy.valueAt(i); + if (policy.template.getMatchRule() == NetworkTemplate.MATCH_WIFI + && !policy.inferred) { + mNetworkPolicy.removeAt(i); + modified = true; + + final String networkId = resolveNetworkId(policy.template.getNetworkId()); + for (WifiConfiguration config : configs) { + if (Objects.equals(resolveNetworkId(config), networkId)) { + Slog.d(TAG, "Found network " + networkId + "; upgrading metered hint"); + config.meteredOverride = policy.metered + ? WifiConfiguration.METERED_OVERRIDE_METERED + : WifiConfiguration.METERED_OVERRIDE_NOT_METERED; + wm.updateNetwork(config); + } + } + } else { + i++; + } + } + if (modified) { + writePolicyAL(); + } + } + void writePolicyAL() { if (LOGV) Slog.v(TAG, "writePolicyAL()"); @@ -2495,81 +2453,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - private NetworkPolicy findPolicyForNetworkNL(NetworkIdentity ident) { - for (int i = mNetworkPolicy.size()-1; i >= 0; i--) { - NetworkPolicy policy = mNetworkPolicy.valueAt(i); - if (policy.template.matches(ident)) { - return policy; - } - } - return null; - } - @Override - public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) { - mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG); - - // only returns usage summary, so we don't require caller to have - // READ_NETWORK_USAGE_HISTORY. + public void setWifiMeteredOverride(String networkId, int meteredOverride) { + mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); final long token = Binder.clearCallingIdentity(); try { - return getNetworkQuotaInfoUnchecked(state); + final WifiManager wm = mContext.getSystemService(WifiManager.class); + final List<WifiConfiguration> configs = wm.getConfiguredNetworks(); + for (WifiConfiguration config : configs) { + if (Objects.equals(resolveNetworkId(config), networkId)) { + config.meteredOverride = meteredOverride; + wm.updateNetwork(config); + } + } } finally { Binder.restoreCallingIdentity(token); } } - private NetworkQuotaInfo getNetworkQuotaInfoUnchecked(NetworkState state) { - final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state); - - final NetworkPolicy policy; - synchronized (mNetworkPoliciesSecondLock) { - policy = findPolicyForNetworkNL(ident); - } - - if (policy == null || !policy.hasCycle()) { - // missing policy means we can't derive useful quota info - return null; - } - - final long currentTime = currentTimeMillis(); - - // find total bytes used under policy - final long start = computeLastCycleBoundary(currentTime, policy); - final long end = currentTime; - final long totalBytes = getTotalBytes(policy.template, start, end); - - // report soft and hard limits under policy - final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes - : NetworkQuotaInfo.NO_LIMIT; - final long hardLimitBytes = policy.limitBytes != LIMIT_DISABLED ? policy.limitBytes - : NetworkQuotaInfo.NO_LIMIT; - - return new NetworkQuotaInfo(totalBytes, softLimitBytes, hardLimitBytes); - } - @Override - public boolean isNetworkMetered(NetworkState state) { - if (state.networkInfo == null) { - return false; - } - - final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state); - - final NetworkPolicy policy; - synchronized (mNetworkPoliciesSecondLock) { - policy = findPolicyForNetworkNL(ident); - } - - if (policy != null) { - return policy.metered; - } else { - final int type = state.networkInfo.getType(); - if ((isNetworkTypeMobile(type) && ident.getMetered()) || type == TYPE_WIMAX) { - return true; - } - return false; - } + @Deprecated + public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) { + Log.w(TAG, "Shame on UID " + Binder.getCallingUid() + + " for calling the hidden API getNetworkQuotaInfo(). Shame!"); + return new NetworkQuotaInfo(); } @Override diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java index 8ced1c22020b..b65b9d7749b2 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java @@ -19,26 +19,17 @@ package com.android.server.net; import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; -import static android.net.wifi.WifiInfo.removeDoubleQuotes; - -import static com.android.server.net.NetworkPolicyManagerService.newWifiPolicy; -import static com.android.server.net.NetworkPolicyManagerService.TAG; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import android.content.Context; import android.net.INetworkPolicyManager; -import android.net.NetworkPolicy; -import android.net.NetworkTemplate; +import android.net.NetworkPolicyManager; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.os.RemoteException; import android.os.ShellCommand; -import android.util.Log; + +import java.io.PrintWriter; +import java.util.List; class NetworkPolicyManagerShellCommand extends ShellCommand { @@ -90,7 +81,7 @@ class NetworkPolicyManagerShellCommand extends ShellCommand { pw.println(" Adds a UID to the blacklist for restrict background usage."); pw.println(" get restrict-background"); pw.println(" Gets the global restrict background usage status."); - pw.println(" list wifi-networks [BOOLEAN]"); + pw.println(" list wifi-networks [true|false]"); pw.println(" Lists all saved wifi networks and whether they are metered or not."); pw.println(" If a boolean argument is passed, filters just the metered (or unmetered)"); pw.println(" networks."); @@ -102,7 +93,7 @@ class NetworkPolicyManagerShellCommand extends ShellCommand { pw.println(" Removes a UID from the whitelist for restrict background usage."); pw.println(" remove restrict-background-blacklist UID"); pw.println(" Removes a UID from the blacklist for restrict background usage."); - pw.println(" set metered-network ID BOOLEAN"); + pw.println(" set metered-network ID [undefined|true|false]"); pw.println(" Toggles whether the given wi-fi network is metered."); pw.println(" set restrict-background BOOLEAN"); pw.println(" Sets the global restrict background usage status."); @@ -276,107 +267,60 @@ class NetworkPolicyManagerShellCommand extends ShellCommand { return resetUidPolicy("not blacklisted", POLICY_REJECT_METERED_BACKGROUND); } - private int listWifiNetworks() throws RemoteException { + private int listWifiNetworks() { final PrintWriter pw = getOutPrintWriter(); final String arg = getNextArg(); - final Boolean filter = arg == null ? null : Boolean.valueOf(arg); - for (NetworkPolicy policy : getWifiPolicies()) { - if (filter != null && filter.booleanValue() != policy.metered) { - continue; + final int match; + if (arg == null) { + match = WifiConfiguration.METERED_OVERRIDE_NONE; + } else if (Boolean.parseBoolean(arg)) { + match = WifiConfiguration.METERED_OVERRIDE_METERED; + } else { + match = WifiConfiguration.METERED_OVERRIDE_NOT_METERED; + } + + final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); + for (WifiConfiguration config : configs) { + if (arg == null || config.meteredOverride == match) { + pw.print(NetworkPolicyManager.resolveNetworkId(config)); + pw.print(';'); + pw.println(overrideToString(config.meteredOverride)); } - pw.print(getNetworkId(policy)); - pw.print(';'); - pw.println(policy.metered); } return 0; } private int setMeteredWifiNetwork() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); - final String id = getNextArg(); - if (id == null) { - pw.println("Error: didn't specify ID"); + final String networkId = getNextArg(); + if (networkId == null) { + pw.println("Error: didn't specify networkId"); return -1; } final String arg = getNextArg(); if (arg == null) { - pw.println("Error: didn't specify BOOLEAN"); + pw.println("Error: didn't specify meteredOverride"); return -1; } - final boolean metered = Boolean.valueOf(arg); - final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null); - boolean changed = false; - // First try to find a policy with such id - for (NetworkPolicy policy : policies) { - if (policy.template.isMatchRuleMobile() || policy.metered == metered) { - continue; - } - final String networkId = getNetworkId(policy); - if (id.equals(networkId)) { - Log.i(TAG, "Changing " + networkId + " metered status to " + metered); - policy.metered = metered; - changed = true; - } - } - if (changed) { - mInterface.setNetworkPolicies(policies); - return 0; - } - // Policy not found: check if there is a saved wi-fi with such id. - for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) { - final String ssid = removeDoubleQuotes(config.SSID); - if (id.equals(ssid)) { - final NetworkPolicy policy = newPolicy(ssid); - policy.metered = true; - Log.i(TAG, "Creating new policy for " + ssid + ": " + policy); - final NetworkPolicy[] newPolicies = new NetworkPolicy[policies.length + 1]; - System.arraycopy(policies, 0, newPolicies, 0, policies.length); - newPolicies[newPolicies.length - 1] = policy; - mInterface.setNetworkPolicies(newPolicies); - return 0; - } - } - pw.print("Error: didn't find network with SSID "); pw.println(id); + mInterface.setWifiMeteredOverride(NetworkPolicyManager.resolveNetworkId(networkId), + stringToOverride(arg)); return -1; } - private List<NetworkPolicy> getWifiPolicies() throws RemoteException { - // First gets a list of saved wi-fi networks. - final List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks(); - final int size = configs != null ? configs.size() : 0; - final Set<String> ssids = new HashSet<>(size); - if (configs != null) { - for (WifiConfiguration config : configs) { - ssids.add(removeDoubleQuotes(config.SSID)); - } - } - - // Then gets the saved policies. - final NetworkPolicy[] policies = mInterface.getNetworkPolicies(null); - final List<NetworkPolicy> wifiPolicies = new ArrayList<NetworkPolicy>(policies.length); - for (NetworkPolicy policy: policies) { - if (!policy.template.isMatchRuleMobile()) { - wifiPolicies.add(policy); - final String netId = getNetworkId(policy); - ssids.remove(netId); - } - } - // Finally, creates new default policies for saved WI-FIs not policied yet. - for (String ssid : ssids) { - final NetworkPolicy policy = newPolicy(ssid); - wifiPolicies.add(policy); + private static String overrideToString(int override) { + switch (override) { + case WifiConfiguration.METERED_OVERRIDE_METERED: return "true"; + case WifiConfiguration.METERED_OVERRIDE_NOT_METERED: return "false"; + default: return "none"; } - return wifiPolicies; } - private NetworkPolicy newPolicy(String ssid) { - final NetworkTemplate template = NetworkTemplate.buildTemplateWifi(ssid); - final NetworkPolicy policy = newWifiPolicy(template, false); - return policy; - } - - private String getNetworkId(NetworkPolicy policy) { - return removeDoubleQuotes(policy.template.getNetworkId()); + private static int stringToOverride(String override) { + switch (override) { + case "true": return WifiConfiguration.METERED_OVERRIDE_METERED; + case "false": return WifiConfiguration.METERED_OVERRIDE_NOT_METERED; + default: return WifiConfiguration.METERED_OVERRIDE_NONE; + } } private int getNextBooleanArg() { diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index e7fbe4fe55fc..13d54abdd005 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -245,6 +245,7 @@ public class WifiConfiguration implements Parcelable { * (e.g., {@code 01a243f405}). */ public String SSID; + /** * When set, this network configuration entry should only be used when * associating with the AP having the specified BSSID. The value is @@ -740,22 +741,58 @@ public class WifiConfiguration implements Parcelable { } /** + * Indicates if the creator of this configuration has expressed that it + * should be considered metered. + * + * @see #isMetered(WifiConfiguration, WifiInfo) * @hide - * A hint about whether or not the network represented by this WifiConfiguration - * is metered. This is hinted at via the meteredHint bit on DHCP results set in - * {@link com.android.server.wifi.WifiStateMachine}, or via a network score in - * {@link com.android.server.wifi.ExternalScoreEvaluator}. */ @SystemApi public boolean meteredHint; + /** {@hide} */ + public static final int METERED_OVERRIDE_NONE = 0; + /** {@hide} */ + public static final int METERED_OVERRIDE_METERED = 1; + /** {@hide} */ + public static final int METERED_OVERRIDE_NOT_METERED = 2; + + /** + * Indicates if the end user has expressed an explicit opinion about the + * meteredness of this network, such as through the Settings app. + * <p> + * This should always override any values from {@link #meteredHint} or + * {@link WifiInfo#getMeteredHint()}. + * + * @see #isMetered(WifiConfiguration, WifiInfo) + * @hide + */ + public int meteredOverride = METERED_OVERRIDE_NONE; + /** + * Blend together all the various opinions to decide if the given network + * should be considered metered or not. + * * @hide - * Indicates if a user has specified the WifiConfiguration to be metered. Users - * can toggle if a network is metered within Settings -> Data Usage -> Network - * Restrictions. */ - public boolean meteredOverride; + public static boolean isMetered(WifiConfiguration config, WifiInfo info) { + boolean metered = false; + if (info != null && info.getMeteredHint()) { + metered = true; + } + if (config != null && config.meteredHint) { + metered = true; + } + if (config != null + && config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED) { + metered = true; + } + if (config != null + && config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_NOT_METERED) { + metered = false; + } + return metered; + } /** * @hide @@ -1426,7 +1463,7 @@ public class WifiConfiguration implements Parcelable { didSelfAdd = false; ephemeral = false; meteredHint = false; - meteredOverride = false; + meteredOverride = METERED_OVERRIDE_NONE; useExternalScores = false; validatedInternetAccess = false; mIpConfiguration = new IpConfiguration(); @@ -1520,23 +1557,24 @@ public class WifiConfiguration implements Parcelable { sbuf.append(this.numNoInternetAccessReports).append("\n"); } if (this.updateTime != null) { - sbuf.append("update ").append(this.updateTime).append("\n"); + sbuf.append(" update ").append(this.updateTime).append("\n"); } if (this.creationTime != null) { - sbuf.append("creation").append(this.creationTime).append("\n"); + sbuf.append(" creation ").append(this.creationTime).append("\n"); } if (this.didSelfAdd) sbuf.append(" didSelfAdd"); if (this.selfAdded) sbuf.append(" selfAdded"); if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess"); if (this.ephemeral) sbuf.append(" ephemeral"); if (this.meteredHint) sbuf.append(" meteredHint"); - if (this.meteredOverride) sbuf.append(" meteredOverride"); if (this.useExternalScores) sbuf.append(" useExternalScores"); if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess - || this.ephemeral || this.meteredHint || this.meteredOverride - || this.useExternalScores) { + || this.ephemeral || this.meteredHint || this.useExternalScores) { sbuf.append("\n"); } + if (this.meteredOverride != METERED_OVERRIDE_NONE) { + sbuf.append(" meteredOverride ").append(meteredOverride).append("\n"); + } sbuf.append(" KeyMgmt:"); for (int k = 0; k < this.allowedKeyManagement.size(); k++) { if (this.allowedKeyManagement.get(k)) { @@ -2062,7 +2100,7 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(isLegacyPasspointConfig ? 1 : 0); dest.writeInt(ephemeral ? 1 : 0); dest.writeInt(meteredHint ? 1 : 0); - dest.writeInt(meteredOverride ? 1 : 0); + dest.writeInt(meteredOverride); dest.writeInt(useExternalScores ? 1 : 0); dest.writeInt(creatorUid); dest.writeInt(lastConnectUid); @@ -2129,7 +2167,7 @@ public class WifiConfiguration implements Parcelable { config.isLegacyPasspointConfig = in.readInt() != 0; config.ephemeral = in.readInt() != 0; config.meteredHint = in.readInt() != 0; - config.meteredOverride = in.readInt() != 0; + config.meteredOverride = in.readInt(); config.useExternalScores = in.readInt() != 0; config.creatorUid = in.readInt(); config.lastConnectUid = in.readInt(); diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index e48f7bdb27ee..bd253562c15e 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -459,7 +459,13 @@ public class WifiInfo implements Parcelable { return mMacAddress != null && !DEFAULT_MAC_ADDRESS.equals(mMacAddress); } - /** {@hide} */ + /** + * Indicates if we've dynamically detected this active network connection as + * being metered. + * + * @see WifiConfiguration#isMetered(WifiConfiguration, WifiInfo) + * @hide + */ public void setMeteredHint(boolean meteredHint) { mMeteredHint = meteredHint; } |