Move module sources to packages/Connectivity
Files that are planned to be part of the connectivity module are grouped in packages/Connectivity, so they can be built separately and moved in one operation with their history into packages/modules/Connectivity. This places the files in the existing framework-connectivity-sources filegroup instead of the current framework-core-sources filegroup. Both are used the same way in framework-non-updatable-sources. Bug: 171540887 Test: m Change-Id: I62d9d91574ace6f5c4624035d190260c3126b91e
This commit is contained in:
171
framework/src/android/net/CaptivePortal.java
Normal file
171
framework/src/android/net/CaptivePortal.java
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed urnder the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* A class allowing apps handling the {@link ConnectivityManager#ACTION_CAPTIVE_PORTAL_SIGN_IN}
|
||||
* activity to indicate to the system different outcomes of captive portal sign in. This class is
|
||||
* passed as an extra named {@link ConnectivityManager#EXTRA_CAPTIVE_PORTAL} with the
|
||||
* {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} activity.
|
||||
*/
|
||||
public class CaptivePortal implements Parcelable {
|
||||
/**
|
||||
* Response code from the captive portal application, indicating that the portal was dismissed
|
||||
* and the network should be re-validated.
|
||||
* @see ICaptivePortal#appResponse(int)
|
||||
* @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int APP_RETURN_DISMISSED = 0;
|
||||
/**
|
||||
* Response code from the captive portal application, indicating that the user did not login and
|
||||
* does not want to use the captive portal network.
|
||||
* @see ICaptivePortal#appResponse(int)
|
||||
* @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int APP_RETURN_UNWANTED = 1;
|
||||
/**
|
||||
* Response code from the captive portal application, indicating that the user does not wish to
|
||||
* login but wants to use the captive portal network as-is.
|
||||
* @see ICaptivePortal#appResponse(int)
|
||||
* @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int APP_RETURN_WANTED_AS_IS = 2;
|
||||
/** Event offset of request codes from captive portal application. */
|
||||
private static final int APP_REQUEST_BASE = 100;
|
||||
/**
|
||||
* Request code from the captive portal application, indicating that the network condition may
|
||||
* have changed and the network should be re-validated.
|
||||
* @see ICaptivePortal#appRequest(int)
|
||||
* @see android.net.INetworkMonitor#forceReevaluation(int)
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int APP_REQUEST_REEVALUATION_REQUIRED = APP_REQUEST_BASE + 0;
|
||||
|
||||
private final IBinder mBinder;
|
||||
|
||||
/** @hide */
|
||||
public CaptivePortal(@NonNull IBinder binder) {
|
||||
mBinder = binder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeStrongBinder(mBinder);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Parcelable.Creator<CaptivePortal> CREATOR
|
||||
= new Parcelable.Creator<CaptivePortal>() {
|
||||
@Override
|
||||
public CaptivePortal createFromParcel(Parcel in) {
|
||||
return new CaptivePortal(in.readStrongBinder());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CaptivePortal[] newArray(int size) {
|
||||
return new CaptivePortal[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicate to the system that the captive portal has been
|
||||
* dismissed. In response the framework will re-evaluate the network's
|
||||
* connectivity and might take further action thereafter.
|
||||
*/
|
||||
public void reportCaptivePortalDismissed() {
|
||||
try {
|
||||
ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_DISMISSED);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate to the system that the user does not want to pursue signing in to the
|
||||
* captive portal and the system should continue to prefer other networks
|
||||
* without captive portals for use as the default active data network. The
|
||||
* system will not retest the network for a captive portal so as to avoid
|
||||
* disturbing the user with further sign in to network notifications.
|
||||
*/
|
||||
public void ignoreNetwork() {
|
||||
try {
|
||||
ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_UNWANTED);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate to the system the user wants to use this network as is, even though
|
||||
* the captive portal is still in place. The system will treat the network
|
||||
* as if it did not have a captive portal when selecting the network to use
|
||||
* as the default active data network. This may result in this network
|
||||
* becoming the default active data network, which could disrupt network
|
||||
* connectivity for apps because the captive portal is still in place.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public void useNetwork() {
|
||||
try {
|
||||
ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_WANTED_AS_IS);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that the system reevaluates the captive portal status.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
|
||||
public void reevaluateNetwork() {
|
||||
try {
|
||||
ICaptivePortal.Stub.asInterface(mBinder).appRequest(APP_REQUEST_REEVALUATION_REQUIRED);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a captive portal login event.
|
||||
* @param eventId one of the CAPTIVE_PORTAL_LOGIN_* constants in metrics_constants.proto.
|
||||
* @param packageName captive portal application package name.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public void logEvent(int eventId, @NonNull String packageName) {
|
||||
try {
|
||||
ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
19
framework/src/android/net/CaptivePortalData.aidl
Normal file
19
framework/src/android/net/CaptivePortalData.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable CaptivePortalData;
|
||||
305
framework/src/android/net/CaptivePortalData.java
Normal file
305
framework/src/android/net/CaptivePortalData.java
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Metadata sent by captive portals, see https://www.ietf.org/id/draft-ietf-capport-api-03.txt.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class CaptivePortalData implements Parcelable {
|
||||
private final long mRefreshTimeMillis;
|
||||
@Nullable
|
||||
private final Uri mUserPortalUrl;
|
||||
@Nullable
|
||||
private final Uri mVenueInfoUrl;
|
||||
private final boolean mIsSessionExtendable;
|
||||
private final long mByteLimit;
|
||||
private final long mExpiryTimeMillis;
|
||||
private final boolean mCaptive;
|
||||
private final String mVenueFriendlyName;
|
||||
|
||||
private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
|
||||
boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive,
|
||||
String venueFriendlyName) {
|
||||
mRefreshTimeMillis = refreshTimeMillis;
|
||||
mUserPortalUrl = userPortalUrl;
|
||||
mVenueInfoUrl = venueInfoUrl;
|
||||
mIsSessionExtendable = isSessionExtendable;
|
||||
mByteLimit = byteLimit;
|
||||
mExpiryTimeMillis = expiryTimeMillis;
|
||||
mCaptive = captive;
|
||||
mVenueFriendlyName = venueFriendlyName;
|
||||
}
|
||||
|
||||
private CaptivePortalData(Parcel p) {
|
||||
this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
|
||||
p.readLong(), p.readLong(), p.readBoolean(), p.readString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeLong(mRefreshTimeMillis);
|
||||
dest.writeParcelable(mUserPortalUrl, 0);
|
||||
dest.writeParcelable(mVenueInfoUrl, 0);
|
||||
dest.writeBoolean(mIsSessionExtendable);
|
||||
dest.writeLong(mByteLimit);
|
||||
dest.writeLong(mExpiryTimeMillis);
|
||||
dest.writeBoolean(mCaptive);
|
||||
dest.writeString(mVenueFriendlyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder to create new {@link CaptivePortalData}.
|
||||
*/
|
||||
public static class Builder {
|
||||
private long mRefreshTime;
|
||||
private Uri mUserPortalUrl;
|
||||
private Uri mVenueInfoUrl;
|
||||
private boolean mIsSessionExtendable;
|
||||
private long mBytesRemaining = -1;
|
||||
private long mExpiryTime = -1;
|
||||
private boolean mCaptive;
|
||||
private String mVenueFriendlyName;
|
||||
|
||||
/**
|
||||
* Create an empty builder.
|
||||
*/
|
||||
public Builder() {}
|
||||
|
||||
/**
|
||||
* Create a builder copying all data from existing {@link CaptivePortalData}.
|
||||
*/
|
||||
public Builder(@Nullable CaptivePortalData data) {
|
||||
if (data == null) return;
|
||||
setRefreshTime(data.mRefreshTimeMillis)
|
||||
.setUserPortalUrl(data.mUserPortalUrl)
|
||||
.setVenueInfoUrl(data.mVenueInfoUrl)
|
||||
.setSessionExtendable(data.mIsSessionExtendable)
|
||||
.setBytesRemaining(data.mByteLimit)
|
||||
.setExpiryTime(data.mExpiryTimeMillis)
|
||||
.setCaptive(data.mCaptive)
|
||||
.setVenueFriendlyName(data.mVenueFriendlyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time at which data was last refreshed, as per {@link System#currentTimeMillis()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setRefreshTime(long refreshTime) {
|
||||
mRefreshTime = refreshTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL to be used for users to login to the portal, if captive.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) {
|
||||
mUserPortalUrl = userPortalUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL that can be used by users to view information about the network venue.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) {
|
||||
mVenueInfoUrl = venueInfoUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the portal supports extending a user session on the portal URL page.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSessionExtendable(boolean sessionExtendable) {
|
||||
mIsSessionExtendable = sessionExtendable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of bytes remaining on the network before the portal closes.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setBytesRemaining(long bytesRemaining) {
|
||||
mBytesRemaining = bytesRemaining;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time at the session will expire, as per {@link System#currentTimeMillis()}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setExpiryTime(long expiryTime) {
|
||||
mExpiryTime = expiryTime;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the network is captive (portal closed).
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCaptive(boolean captive) {
|
||||
mCaptive = captive;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the venue friendly name.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setVenueFriendlyName(@Nullable String venueFriendlyName) {
|
||||
mVenueFriendlyName = venueFriendlyName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link CaptivePortalData}.
|
||||
*/
|
||||
@NonNull
|
||||
public CaptivePortalData build() {
|
||||
return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl,
|
||||
mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive,
|
||||
mVenueFriendlyName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time at which data was last refreshed, as per {@link System#currentTimeMillis()}.
|
||||
*/
|
||||
public long getRefreshTimeMillis() {
|
||||
return mRefreshTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL to be used for users to login to the portal, or extend their session if
|
||||
* {@link #isSessionExtendable()} is true.
|
||||
*/
|
||||
@Nullable
|
||||
public Uri getUserPortalUrl() {
|
||||
return mUserPortalUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL that can be used by users to view information about the network venue.
|
||||
*/
|
||||
@Nullable
|
||||
public Uri getVenueInfoUrl() {
|
||||
return mVenueInfoUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the user portal URL can be used to extend sessions, when the user is logged
|
||||
* in and the session has a time or byte limit.
|
||||
*/
|
||||
public boolean isSessionExtendable() {
|
||||
return mIsSessionExtendable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remaining bytes on the captive portal session, at the time {@link CaptivePortalData}
|
||||
* was refreshed. This may be different from the limit currently enforced by the portal.
|
||||
* @return The byte limit, or -1 if not set.
|
||||
*/
|
||||
public long getByteLimit() {
|
||||
return mByteLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time at the session will expire, as per {@link System#currentTimeMillis()}.
|
||||
* @return The expiry time, or -1 if unset.
|
||||
*/
|
||||
public long getExpiryTimeMillis() {
|
||||
return mExpiryTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the network is captive (portal closed).
|
||||
*/
|
||||
public boolean isCaptive() {
|
||||
return mCaptive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the venue friendly name
|
||||
*/
|
||||
@Nullable
|
||||
public String getVenueFriendlyName() {
|
||||
return mVenueFriendlyName;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<CaptivePortalData> CREATOR = new Creator<CaptivePortalData>() {
|
||||
@Override
|
||||
public CaptivePortalData createFromParcel(Parcel source) {
|
||||
return new CaptivePortalData(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CaptivePortalData[] newArray(int size) {
|
||||
return new CaptivePortalData[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl,
|
||||
mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof CaptivePortalData)) return false;
|
||||
final CaptivePortalData other = (CaptivePortalData) obj;
|
||||
return mRefreshTimeMillis == other.mRefreshTimeMillis
|
||||
&& Objects.equals(mUserPortalUrl, other.mUserPortalUrl)
|
||||
&& Objects.equals(mVenueInfoUrl, other.mVenueInfoUrl)
|
||||
&& mIsSessionExtendable == other.mIsSessionExtendable
|
||||
&& mByteLimit == other.mByteLimit
|
||||
&& mExpiryTimeMillis == other.mExpiryTimeMillis
|
||||
&& mCaptive == other.mCaptive
|
||||
&& Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CaptivePortalData {"
|
||||
+ "refreshTime: " + mRefreshTimeMillis
|
||||
+ ", userPortalUrl: " + mUserPortalUrl
|
||||
+ ", venueInfoUrl: " + mVenueInfoUrl
|
||||
+ ", isSessionExtendable: " + mIsSessionExtendable
|
||||
+ ", byteLimit: " + mByteLimit
|
||||
+ ", expiryTime: " + mExpiryTimeMillis
|
||||
+ ", captive: " + mCaptive
|
||||
+ ", venueFriendlyName: " + mVenueFriendlyName
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
20
framework/src/android/net/ConnectionInfo.aidl
Normal file
20
framework/src/android/net/ConnectionInfo.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2018 The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
parcelable ConnectionInfo;
|
||||
83
framework/src/android/net/ConnectionInfo.java
Normal file
83
framework/src/android/net/ConnectionInfo.java
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* Describe a network connection including local and remote address/port of a connection and the
|
||||
* transport protocol.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class ConnectionInfo implements Parcelable {
|
||||
public final int protocol;
|
||||
public final InetSocketAddress local;
|
||||
public final InetSocketAddress remote;
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ConnectionInfo(int protocol, InetSocketAddress local, InetSocketAddress remote) {
|
||||
this.protocol = protocol;
|
||||
this.local = local;
|
||||
this.remote = remote;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeInt(protocol);
|
||||
out.writeByteArray(local.getAddress().getAddress());
|
||||
out.writeInt(local.getPort());
|
||||
out.writeByteArray(remote.getAddress().getAddress());
|
||||
out.writeInt(remote.getPort());
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<ConnectionInfo> CREATOR = new Creator<ConnectionInfo>() {
|
||||
public ConnectionInfo createFromParcel(Parcel in) {
|
||||
int protocol = in.readInt();
|
||||
InetAddress localAddress;
|
||||
try {
|
||||
localAddress = InetAddress.getByAddress(in.createByteArray());
|
||||
} catch (UnknownHostException e) {
|
||||
throw new IllegalArgumentException("Invalid InetAddress");
|
||||
}
|
||||
int localPort = in.readInt();
|
||||
InetAddress remoteAddress;
|
||||
try {
|
||||
remoteAddress = InetAddress.getByAddress(in.createByteArray());
|
||||
} catch (UnknownHostException e) {
|
||||
throw new IllegalArgumentException("Invalid InetAddress");
|
||||
}
|
||||
int remotePort = in.readInt();
|
||||
InetSocketAddress local = new InetSocketAddress(localAddress, localPort);
|
||||
InetSocketAddress remote = new InetSocketAddress(remoteAddress, remotePort);
|
||||
return new ConnectionInfo(protocol, local, remote);
|
||||
}
|
||||
|
||||
public ConnectionInfo[] newArray(int size) {
|
||||
return new ConnectionInfo[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
parcelable ConnectivityDiagnosticsManager.ConnectivityReport;
|
||||
parcelable ConnectivityDiagnosticsManager.DataStallReport;
|
||||
777
framework/src/android/net/ConnectivityDiagnosticsManager.java
Normal file
777
framework/src/android/net/ConnectivityDiagnosticsManager.java
Normal file
@@ -0,0 +1,777 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.StringDef;
|
||||
import android.content.Context;
|
||||
import android.os.Binder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Class that provides utilities for collecting network connectivity diagnostics information.
|
||||
* Connectivity information is made available through triggerable diagnostics tools and by listening
|
||||
* to System validations. Some diagnostics information may be permissions-restricted.
|
||||
*
|
||||
* <p>ConnectivityDiagnosticsManager is intended for use by applications offering network
|
||||
* connectivity on a user device. These tools will provide several mechanisms for these applications
|
||||
* to be alerted to network conditions as well as diagnose potential network issues themselves.
|
||||
*
|
||||
* <p>The primary responsibilities of this class are to:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Allow permissioned applications to register and unregister callbacks for network event
|
||||
* notifications
|
||||
* <li>Invoke callbacks for network event notifications, including:
|
||||
* <ul>
|
||||
* <li>Network validations
|
||||
* <li>Data stalls
|
||||
* <li>Connectivity reports from applications
|
||||
* </ul>
|
||||
* </ul>
|
||||
*/
|
||||
public class ConnectivityDiagnosticsManager {
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public static final Map<ConnectivityDiagnosticsCallback, ConnectivityDiagnosticsBinder>
|
||||
sCallbacks = new ConcurrentHashMap<>();
|
||||
|
||||
private final Context mContext;
|
||||
private final IConnectivityManager mService;
|
||||
|
||||
/** @hide */
|
||||
public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) {
|
||||
mContext = Preconditions.checkNotNull(context, "missing context");
|
||||
mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public static boolean persistableBundleEquals(
|
||||
@Nullable PersistableBundle a, @Nullable PersistableBundle b) {
|
||||
if (a == b) return true;
|
||||
if (a == null || b == null) return false;
|
||||
if (!Objects.equals(a.keySet(), b.keySet())) return false;
|
||||
for (String key : a.keySet()) {
|
||||
if (!Objects.equals(a.get(key), b.get(key))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Class that includes connectivity information for a specific Network at a specific time. */
|
||||
public static final class ConnectivityReport implements Parcelable {
|
||||
/**
|
||||
* The overall status of the network is that it is invalid; it neither provides
|
||||
* connectivity nor has been exempted from validation.
|
||||
*/
|
||||
public static final int NETWORK_VALIDATION_RESULT_INVALID = 0;
|
||||
|
||||
/**
|
||||
* The overall status of the network is that it is valid, this may be because it provides
|
||||
* full Internet access (all probes succeeded), or because other properties of the network
|
||||
* caused probes not to be run.
|
||||
*/
|
||||
// TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID
|
||||
public static final int NETWORK_VALIDATION_RESULT_VALID = 1;
|
||||
|
||||
/**
|
||||
* The overall status of the network is that it provides partial connectivity; some
|
||||
* probed services succeeded but others failed.
|
||||
*/
|
||||
// TODO: link to INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
|
||||
public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2;
|
||||
|
||||
/**
|
||||
* Due to the properties of the network, validation was not performed.
|
||||
*/
|
||||
public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(
|
||||
prefix = {"NETWORK_VALIDATION_RESULT_"},
|
||||
value = {
|
||||
NETWORK_VALIDATION_RESULT_INVALID,
|
||||
NETWORK_VALIDATION_RESULT_VALID,
|
||||
NETWORK_VALIDATION_RESULT_PARTIALLY_VALID,
|
||||
NETWORK_VALIDATION_RESULT_SKIPPED
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface NetworkValidationResult {}
|
||||
|
||||
/**
|
||||
* The overall validation result for the Network being reported on.
|
||||
*
|
||||
* <p>The possible values for this key are:
|
||||
* {@link #NETWORK_VALIDATION_RESULT_INVALID},
|
||||
* {@link #NETWORK_VALIDATION_RESULT_VALID},
|
||||
* {@link #NETWORK_VALIDATION_RESULT_PARTIALLY_VALID},
|
||||
* {@link #NETWORK_VALIDATION_RESULT_SKIPPED}.
|
||||
*
|
||||
* @see android.net.NetworkCapabilities#NET_CAPABILITY_VALIDATED
|
||||
*/
|
||||
@NetworkValidationResult
|
||||
public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
|
||||
|
||||
/** DNS probe. */
|
||||
// TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS
|
||||
public static final int NETWORK_PROBE_DNS = 0x04;
|
||||
|
||||
/** HTTP probe. */
|
||||
// TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP
|
||||
public static final int NETWORK_PROBE_HTTP = 0x08;
|
||||
|
||||
/** HTTPS probe. */
|
||||
// TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTPS;
|
||||
public static final int NETWORK_PROBE_HTTPS = 0x10;
|
||||
|
||||
/** Captive portal fallback probe. */
|
||||
// TODO: link to INetworkMonitor.NETWORK_VALIDATION_FALLBACK
|
||||
public static final int NETWORK_PROBE_FALLBACK = 0x20;
|
||||
|
||||
/** Private DNS (DNS over TLS) probd. */
|
||||
// TODO: link to INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS
|
||||
public static final int NETWORK_PROBE_PRIVATE_DNS = 0x40;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(
|
||||
prefix = {"NETWORK_PROBE_"},
|
||||
value = {
|
||||
NETWORK_PROBE_DNS,
|
||||
NETWORK_PROBE_HTTP,
|
||||
NETWORK_PROBE_HTTPS,
|
||||
NETWORK_PROBE_FALLBACK,
|
||||
NETWORK_PROBE_PRIVATE_DNS
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface NetworkProbe {}
|
||||
|
||||
/**
|
||||
* A bitmask of network validation probes that succeeded.
|
||||
*
|
||||
* <p>The possible bits values reported by this key are:
|
||||
* {@link #NETWORK_PROBE_DNS},
|
||||
* {@link #NETWORK_PROBE_HTTP},
|
||||
* {@link #NETWORK_PROBE_HTTPS},
|
||||
* {@link #NETWORK_PROBE_FALLBACK},
|
||||
* {@link #NETWORK_PROBE_PRIVATE_DNS}.
|
||||
*/
|
||||
@NetworkProbe
|
||||
public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK =
|
||||
"networkProbesSucceeded";
|
||||
|
||||
/**
|
||||
* A bitmask of network validation probes that were attempted.
|
||||
*
|
||||
* <p>These probes may have failed or may be incomplete at the time of this report.
|
||||
*
|
||||
* <p>The possible bits values reported by this key are:
|
||||
* {@link #NETWORK_PROBE_DNS},
|
||||
* {@link #NETWORK_PROBE_HTTP},
|
||||
* {@link #NETWORK_PROBE_HTTPS},
|
||||
* {@link #NETWORK_PROBE_FALLBACK},
|
||||
* {@link #NETWORK_PROBE_PRIVATE_DNS}.
|
||||
*/
|
||||
@NetworkProbe
|
||||
public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK =
|
||||
"networkProbesAttempted";
|
||||
|
||||
/** @hide */
|
||||
@StringDef(prefix = {"KEY_"}, value = {
|
||||
KEY_NETWORK_VALIDATION_RESULT, KEY_NETWORK_PROBES_SUCCEEDED_BITMASK,
|
||||
KEY_NETWORK_PROBES_ATTEMPTED_BITMASK})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ConnectivityReportBundleKeys {}
|
||||
|
||||
/** The Network for which this ConnectivityReport applied */
|
||||
@NonNull private final Network mNetwork;
|
||||
|
||||
/**
|
||||
* The timestamp for the report. The timestamp is taken from {@link
|
||||
* System#currentTimeMillis}.
|
||||
*/
|
||||
private final long mReportTimestamp;
|
||||
|
||||
/** LinkProperties available on the Network at the reported timestamp */
|
||||
@NonNull private final LinkProperties mLinkProperties;
|
||||
|
||||
/** NetworkCapabilities available on the Network at the reported timestamp */
|
||||
@NonNull private final NetworkCapabilities mNetworkCapabilities;
|
||||
|
||||
/** PersistableBundle that may contain additional info about the report */
|
||||
@NonNull private final PersistableBundle mAdditionalInfo;
|
||||
|
||||
/**
|
||||
* Constructor for ConnectivityReport.
|
||||
*
|
||||
* <p>Apps should obtain instances through {@link
|
||||
* ConnectivityDiagnosticsCallback#onConnectivityReportAvailable} instead of instantiating
|
||||
* their own instances (unless for testing purposes).
|
||||
*
|
||||
* @param network The Network for which this ConnectivityReport applies
|
||||
* @param reportTimestamp The timestamp for the report
|
||||
* @param linkProperties The LinkProperties available on network at reportTimestamp
|
||||
* @param networkCapabilities The NetworkCapabilities available on network at
|
||||
* reportTimestamp
|
||||
* @param additionalInfo A PersistableBundle that may contain additional info about the
|
||||
* report
|
||||
*/
|
||||
public ConnectivityReport(
|
||||
@NonNull Network network,
|
||||
long reportTimestamp,
|
||||
@NonNull LinkProperties linkProperties,
|
||||
@NonNull NetworkCapabilities networkCapabilities,
|
||||
@NonNull PersistableBundle additionalInfo) {
|
||||
mNetwork = network;
|
||||
mReportTimestamp = reportTimestamp;
|
||||
mLinkProperties = new LinkProperties(linkProperties);
|
||||
mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
|
||||
mAdditionalInfo = additionalInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Network for this ConnectivityReport.
|
||||
*
|
||||
* @return The Network for which this ConnectivityReport applied
|
||||
*/
|
||||
@NonNull
|
||||
public Network getNetwork() {
|
||||
return mNetwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the epoch timestamp (milliseconds) for when this report was taken.
|
||||
*
|
||||
* @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
|
||||
*/
|
||||
public long getReportTimestamp() {
|
||||
return mReportTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LinkProperties available when this report was taken.
|
||||
*
|
||||
* @return LinkProperties available on the Network at the reported timestamp
|
||||
*/
|
||||
@NonNull
|
||||
public LinkProperties getLinkProperties() {
|
||||
return new LinkProperties(mLinkProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the NetworkCapabilities when this report was taken.
|
||||
*
|
||||
* @return NetworkCapabilities available on the Network at the reported timestamp
|
||||
*/
|
||||
@NonNull
|
||||
public NetworkCapabilities getNetworkCapabilities() {
|
||||
return new NetworkCapabilities(mNetworkCapabilities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PersistableBundle with additional info for this report.
|
||||
*
|
||||
* @return PersistableBundle that may contain additional info about the report
|
||||
*/
|
||||
@NonNull
|
||||
public PersistableBundle getAdditionalInfo() {
|
||||
return new PersistableBundle(mAdditionalInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof ConnectivityReport)) return false;
|
||||
final ConnectivityReport that = (ConnectivityReport) o;
|
||||
|
||||
// PersistableBundle is optimized to avoid unparcelling data unless fields are
|
||||
// referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
|
||||
// {@link PersistableBundle#kindofEquals}.
|
||||
return mReportTimestamp == that.mReportTimestamp
|
||||
&& mNetwork.equals(that.mNetwork)
|
||||
&& mLinkProperties.equals(that.mLinkProperties)
|
||||
&& mNetworkCapabilities.equals(that.mNetworkCapabilities)
|
||||
&& persistableBundleEquals(mAdditionalInfo, that.mAdditionalInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(
|
||||
mNetwork,
|
||||
mReportTimestamp,
|
||||
mLinkProperties,
|
||||
mNetworkCapabilities,
|
||||
mAdditionalInfo);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mNetwork, flags);
|
||||
dest.writeLong(mReportTimestamp);
|
||||
dest.writeParcelable(mLinkProperties, flags);
|
||||
dest.writeParcelable(mNetworkCapabilities, flags);
|
||||
dest.writeParcelable(mAdditionalInfo, flags);
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public static final @NonNull Creator<ConnectivityReport> CREATOR =
|
||||
new Creator<ConnectivityReport>() {
|
||||
public ConnectivityReport createFromParcel(Parcel in) {
|
||||
return new ConnectivityReport(
|
||||
in.readParcelable(null),
|
||||
in.readLong(),
|
||||
in.readParcelable(null),
|
||||
in.readParcelable(null),
|
||||
in.readParcelable(null));
|
||||
}
|
||||
|
||||
public ConnectivityReport[] newArray(int size) {
|
||||
return new ConnectivityReport[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Class that includes information for a suspected data stall on a specific Network */
|
||||
public static final class DataStallReport implements Parcelable {
|
||||
/**
|
||||
* Indicates that the Data Stall was detected using DNS events.
|
||||
*/
|
||||
public static final int DETECTION_METHOD_DNS_EVENTS = 1;
|
||||
|
||||
/**
|
||||
* Indicates that the Data Stall was detected using TCP metrics.
|
||||
*/
|
||||
public static final int DETECTION_METHOD_TCP_METRICS = 2;
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(
|
||||
prefix = {"DETECTION_METHOD_"},
|
||||
value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS})
|
||||
public @interface DetectionMethod {}
|
||||
|
||||
/**
|
||||
* This key represents the period in milliseconds over which other included TCP metrics
|
||||
* were measured.
|
||||
*
|
||||
* <p>This key will be included if the data stall detection method is
|
||||
* {@link #DETECTION_METHOD_TCP_METRICS}.
|
||||
*
|
||||
* <p>This value is an int.
|
||||
*/
|
||||
public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS =
|
||||
"tcpMetricsCollectionPeriodMillis";
|
||||
|
||||
/**
|
||||
* This key represents the fail rate of TCP packets when the suspected data stall was
|
||||
* detected.
|
||||
*
|
||||
* <p>This key will be included if the data stall detection method is
|
||||
* {@link #DETECTION_METHOD_TCP_METRICS}.
|
||||
*
|
||||
* <p>This value is an int percentage between 0 and 100.
|
||||
*/
|
||||
public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
|
||||
|
||||
/**
|
||||
* This key represents the consecutive number of DNS timeouts that have occurred.
|
||||
*
|
||||
* <p>The consecutive count will be reset any time a DNS response is received.
|
||||
*
|
||||
* <p>This key will be included if the data stall detection method is
|
||||
* {@link #DETECTION_METHOD_DNS_EVENTS}.
|
||||
*
|
||||
* <p>This value is an int.
|
||||
*/
|
||||
public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@StringDef(prefix = {"KEY_"}, value = {
|
||||
KEY_TCP_PACKET_FAIL_RATE,
|
||||
KEY_DNS_CONSECUTIVE_TIMEOUTS
|
||||
})
|
||||
public @interface DataStallReportBundleKeys {}
|
||||
|
||||
/** The Network for which this DataStallReport applied */
|
||||
@NonNull private final Network mNetwork;
|
||||
|
||||
/**
|
||||
* The timestamp for the report. The timestamp is taken from {@link
|
||||
* System#currentTimeMillis}.
|
||||
*/
|
||||
private long mReportTimestamp;
|
||||
|
||||
/** A bitmask of the detection methods used to identify the suspected data stall */
|
||||
@DetectionMethod private final int mDetectionMethod;
|
||||
|
||||
/** LinkProperties available on the Network at the reported timestamp */
|
||||
@NonNull private final LinkProperties mLinkProperties;
|
||||
|
||||
/** NetworkCapabilities available on the Network at the reported timestamp */
|
||||
@NonNull private final NetworkCapabilities mNetworkCapabilities;
|
||||
|
||||
/** PersistableBundle that may contain additional information on the suspected data stall */
|
||||
@NonNull private final PersistableBundle mStallDetails;
|
||||
|
||||
/**
|
||||
* Constructor for DataStallReport.
|
||||
*
|
||||
* <p>Apps should obtain instances through {@link
|
||||
* ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own
|
||||
* instances (unless for testing purposes).
|
||||
*
|
||||
* @param network The Network for which this DataStallReport applies
|
||||
* @param reportTimestamp The timestamp for the report
|
||||
* @param detectionMethod The detection method used to identify this data stall
|
||||
* @param linkProperties The LinkProperties available on network at reportTimestamp
|
||||
* @param networkCapabilities The NetworkCapabilities available on network at
|
||||
* reportTimestamp
|
||||
* @param stallDetails A PersistableBundle that may contain additional info about the report
|
||||
*/
|
||||
public DataStallReport(
|
||||
@NonNull Network network,
|
||||
long reportTimestamp,
|
||||
@DetectionMethod int detectionMethod,
|
||||
@NonNull LinkProperties linkProperties,
|
||||
@NonNull NetworkCapabilities networkCapabilities,
|
||||
@NonNull PersistableBundle stallDetails) {
|
||||
mNetwork = network;
|
||||
mReportTimestamp = reportTimestamp;
|
||||
mDetectionMethod = detectionMethod;
|
||||
mLinkProperties = new LinkProperties(linkProperties);
|
||||
mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
|
||||
mStallDetails = stallDetails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Network for this DataStallReport.
|
||||
*
|
||||
* @return The Network for which this DataStallReport applied
|
||||
*/
|
||||
@NonNull
|
||||
public Network getNetwork() {
|
||||
return mNetwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the epoch timestamp (milliseconds) for when this report was taken.
|
||||
*
|
||||
* @return The timestamp for the report. Taken from {@link System#currentTimeMillis}.
|
||||
*/
|
||||
public long getReportTimestamp() {
|
||||
return mReportTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bitmask of detection methods used to identify this suspected data stall.
|
||||
*
|
||||
* @return The bitmask of detection methods used to identify the suspected data stall
|
||||
*/
|
||||
public int getDetectionMethod() {
|
||||
return mDetectionMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LinkProperties available when this report was taken.
|
||||
*
|
||||
* @return LinkProperties available on the Network at the reported timestamp
|
||||
*/
|
||||
@NonNull
|
||||
public LinkProperties getLinkProperties() {
|
||||
return new LinkProperties(mLinkProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the NetworkCapabilities when this report was taken.
|
||||
*
|
||||
* @return NetworkCapabilities available on the Network at the reported timestamp
|
||||
*/
|
||||
@NonNull
|
||||
public NetworkCapabilities getNetworkCapabilities() {
|
||||
return new NetworkCapabilities(mNetworkCapabilities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PersistableBundle with additional info for this report.
|
||||
*
|
||||
* <p>Gets a bundle with details about the suspected data stall including information
|
||||
* specific to the monitoring method that detected the data stall.
|
||||
*
|
||||
* @return PersistableBundle that may contain additional information on the suspected data
|
||||
* stall
|
||||
*/
|
||||
@NonNull
|
||||
public PersistableBundle getStallDetails() {
|
||||
return new PersistableBundle(mStallDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof DataStallReport)) return false;
|
||||
final DataStallReport that = (DataStallReport) o;
|
||||
|
||||
// PersistableBundle is optimized to avoid unparcelling data unless fields are
|
||||
// referenced. Because of this, use {@link ConnectivityDiagnosticsManager#equals} over
|
||||
// {@link PersistableBundle#kindofEquals}.
|
||||
return mReportTimestamp == that.mReportTimestamp
|
||||
&& mDetectionMethod == that.mDetectionMethod
|
||||
&& mNetwork.equals(that.mNetwork)
|
||||
&& mLinkProperties.equals(that.mLinkProperties)
|
||||
&& mNetworkCapabilities.equals(that.mNetworkCapabilities)
|
||||
&& persistableBundleEquals(mStallDetails, that.mStallDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(
|
||||
mNetwork,
|
||||
mReportTimestamp,
|
||||
mDetectionMethod,
|
||||
mLinkProperties,
|
||||
mNetworkCapabilities,
|
||||
mStallDetails);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeParcelable(mNetwork, flags);
|
||||
dest.writeLong(mReportTimestamp);
|
||||
dest.writeInt(mDetectionMethod);
|
||||
dest.writeParcelable(mLinkProperties, flags);
|
||||
dest.writeParcelable(mNetworkCapabilities, flags);
|
||||
dest.writeParcelable(mStallDetails, flags);
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public static final @NonNull Creator<DataStallReport> CREATOR =
|
||||
new Creator<DataStallReport>() {
|
||||
public DataStallReport createFromParcel(Parcel in) {
|
||||
return new DataStallReport(
|
||||
in.readParcelable(null),
|
||||
in.readLong(),
|
||||
in.readInt(),
|
||||
in.readParcelable(null),
|
||||
in.readParcelable(null),
|
||||
in.readParcelable(null));
|
||||
}
|
||||
|
||||
public DataStallReport[] newArray(int size) {
|
||||
return new DataStallReport[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public static class ConnectivityDiagnosticsBinder
|
||||
extends IConnectivityDiagnosticsCallback.Stub {
|
||||
@NonNull private final ConnectivityDiagnosticsCallback mCb;
|
||||
@NonNull private final Executor mExecutor;
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public ConnectivityDiagnosticsBinder(
|
||||
@NonNull ConnectivityDiagnosticsCallback cb, @NonNull Executor executor) {
|
||||
this.mCb = cb;
|
||||
this.mExecutor = executor;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> {
|
||||
mCb.onConnectivityReportAvailable(report);
|
||||
});
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public void onDataStallSuspected(@NonNull DataStallReport report) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> {
|
||||
mCb.onDataStallSuspected(report);
|
||||
});
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public void onNetworkConnectivityReported(
|
||||
@NonNull Network network, boolean hasConnectivity) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> {
|
||||
mCb.onNetworkConnectivityReported(network, hasConnectivity);
|
||||
});
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about
|
||||
* network connectivity events. Must be extended by applications wanting notifications.
|
||||
*/
|
||||
public abstract static class ConnectivityDiagnosticsCallback {
|
||||
/**
|
||||
* Called when the platform completes a data connectivity check. This will also be invoked
|
||||
* immediately upon registration for each network matching the request with the latest
|
||||
* report, if a report has already been generated for that network.
|
||||
*
|
||||
* <p>The Network specified in the ConnectivityReport may not be active any more when this
|
||||
* method is invoked.
|
||||
*
|
||||
* @param report The ConnectivityReport containing information about a connectivity check
|
||||
*/
|
||||
public void onConnectivityReportAvailable(@NonNull ConnectivityReport report) {}
|
||||
|
||||
/**
|
||||
* Called when the platform suspects a data stall on some Network.
|
||||
*
|
||||
* <p>The Network specified in the DataStallReport may not be active any more when this
|
||||
* method is invoked.
|
||||
*
|
||||
* @param report The DataStallReport containing information about the suspected data stall
|
||||
*/
|
||||
public void onDataStallSuspected(@NonNull DataStallReport report) {}
|
||||
|
||||
/**
|
||||
* Called when any app reports connectivity to the System.
|
||||
*
|
||||
* @param network The Network for which connectivity has been reported
|
||||
* @param hasConnectivity The connectivity reported to the System
|
||||
*/
|
||||
public void onNetworkConnectivityReported(
|
||||
@NonNull Network network, boolean hasConnectivity) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a ConnectivityDiagnosticsCallback with the System.
|
||||
*
|
||||
* <p>Only apps that offer network connectivity to the user should be registering callbacks.
|
||||
* These are the only apps whose callbacks will be invoked by the system. Apps considered to
|
||||
* meet these conditions include:
|
||||
*
|
||||
* <ul>
|
||||
* <li>Carrier apps with active subscriptions
|
||||
* <li>Active VPNs
|
||||
* <li>WiFi Suggesters
|
||||
* </ul>
|
||||
*
|
||||
* <p>Callbacks registered by apps not meeting the above criteria will not be invoked.
|
||||
*
|
||||
* <p>If a registering app loses its relevant permissions, any callbacks it registered will
|
||||
* silently stop receiving callbacks.
|
||||
*
|
||||
* <p>Each register() call <b>MUST</b> use a ConnectivityDiagnosticsCallback instance that is
|
||||
* not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with
|
||||
* multiple NetworkRequests, an IllegalArgumentException will be thrown.
|
||||
*
|
||||
* <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
|
||||
* number of outstanding requests to 100 per app (identified by their UID), shared with
|
||||
* callbacks in {@link ConnectivityManager}. Registering a callback with this method will count
|
||||
* toward this limit. If this limit is exceeded, an exception will be thrown. To avoid hitting
|
||||
* this issue and to conserve resources, make sure to unregister the callbacks with
|
||||
* {@link #unregisterConnectivityDiagnosticsCallback}.
|
||||
*
|
||||
* @param request The NetworkRequest that will be used to match with Networks for which
|
||||
* callbacks will be fired
|
||||
* @param e The Executor to be used for running the callback method invocations
|
||||
* @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the
|
||||
* System
|
||||
* @throws IllegalArgumentException if the same callback instance is registered with multiple
|
||||
* NetworkRequests
|
||||
* @throws RuntimeException if the app already has too many callbacks registered.
|
||||
*/
|
||||
public void registerConnectivityDiagnosticsCallback(
|
||||
@NonNull NetworkRequest request,
|
||||
@NonNull Executor e,
|
||||
@NonNull ConnectivityDiagnosticsCallback callback) {
|
||||
final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e);
|
||||
if (sCallbacks.putIfAbsent(callback, binder) != null) {
|
||||
throw new IllegalArgumentException("Callback is currently registered");
|
||||
}
|
||||
|
||||
try {
|
||||
mService.registerConnectivityDiagnosticsCallback(
|
||||
binder, request, mContext.getOpPackageName());
|
||||
} catch (RemoteException exception) {
|
||||
exception.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a ConnectivityDiagnosticsCallback with the System.
|
||||
*
|
||||
* <p>If the given callback is not currently registered with the System, this operation will be
|
||||
* a no-op.
|
||||
*
|
||||
* @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System.
|
||||
*/
|
||||
public void unregisterConnectivityDiagnosticsCallback(
|
||||
@NonNull ConnectivityDiagnosticsCallback callback) {
|
||||
// unconditionally removing from sCallbacks prevents race conditions here, since remove() is
|
||||
// atomic.
|
||||
final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback);
|
||||
if (binder == null) return;
|
||||
|
||||
try {
|
||||
mService.unregisterConnectivityDiagnosticsCallback(binder);
|
||||
} catch (RemoteException exception) {
|
||||
exception.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
5058
framework/src/android/net/ConnectivityManager.java
Normal file
5058
framework/src/android/net/ConnectivityManager.java
Normal file
File diff suppressed because it is too large
Load Diff
20
framework/src/android/net/ConnectivityMetricsEvent.aidl
Normal file
20
framework/src/android/net/ConnectivityMetricsEvent.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
/** {@hide} */
|
||||
parcelable ConnectivityMetricsEvent;
|
||||
56
framework/src/android/net/ConnectivityThread.java
Normal file
56
framework/src/android/net/ConnectivityThread.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
|
||||
/**
|
||||
* Shared singleton connectivity thread for the system. This is a thread for
|
||||
* connectivity operations such as AsyncChannel connections to system services.
|
||||
* Various connectivity manager objects can use this singleton as a common
|
||||
* resource for their handlers instead of creating separate threads of their own.
|
||||
* @hide
|
||||
*/
|
||||
public final class ConnectivityThread extends HandlerThread {
|
||||
|
||||
// A class implementing the lazy holder idiom: the unique static instance
|
||||
// of ConnectivityThread is instantiated in a thread-safe way (guaranteed by
|
||||
// the language specs) the first time that Singleton is referenced in get()
|
||||
// or getInstanceLooper().
|
||||
private static class Singleton {
|
||||
private static final ConnectivityThread INSTANCE = createInstance();
|
||||
}
|
||||
|
||||
private ConnectivityThread() {
|
||||
super("ConnectivityThread");
|
||||
}
|
||||
|
||||
private static ConnectivityThread createInstance() {
|
||||
ConnectivityThread t = new ConnectivityThread();
|
||||
t.start();
|
||||
return t;
|
||||
}
|
||||
|
||||
public static ConnectivityThread get() {
|
||||
return Singleton.INSTANCE;
|
||||
}
|
||||
|
||||
public static Looper getInstanceLooper() {
|
||||
return Singleton.INSTANCE.getLooper();
|
||||
}
|
||||
}
|
||||
19
framework/src/android/net/DhcpInfo.aidl
Normal file
19
framework/src/android/net/DhcpInfo.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
parcelable DhcpInfo;
|
||||
105
framework/src/android/net/DhcpInfo.java
Normal file
105
framework/src/android/net/DhcpInfo.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* A simple object for retrieving the results of a DHCP request.
|
||||
*/
|
||||
public class DhcpInfo implements Parcelable {
|
||||
public int ipAddress;
|
||||
public int gateway;
|
||||
public int netmask;
|
||||
public int dns1;
|
||||
public int dns2;
|
||||
public int serverAddress;
|
||||
|
||||
public int leaseDuration;
|
||||
|
||||
public DhcpInfo() {
|
||||
super();
|
||||
}
|
||||
|
||||
/** copy constructor {@hide} */
|
||||
public DhcpInfo(DhcpInfo source) {
|
||||
if (source != null) {
|
||||
ipAddress = source.ipAddress;
|
||||
gateway = source.gateway;
|
||||
netmask = source.netmask;
|
||||
dns1 = source.dns1;
|
||||
dns2 = source.dns2;
|
||||
serverAddress = source.serverAddress;
|
||||
leaseDuration = source.leaseDuration;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer str = new StringBuffer();
|
||||
|
||||
str.append("ipaddr "); putAddress(str, ipAddress);
|
||||
str.append(" gateway "); putAddress(str, gateway);
|
||||
str.append(" netmask "); putAddress(str, netmask);
|
||||
str.append(" dns1 "); putAddress(str, dns1);
|
||||
str.append(" dns2 "); putAddress(str, dns2);
|
||||
str.append(" DHCP server "); putAddress(str, serverAddress);
|
||||
str.append(" lease ").append(leaseDuration).append(" seconds");
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
private static void putAddress(StringBuffer buf, int addr) {
|
||||
buf.append(NetworkUtils.intToInetAddress(addr).getHostAddress());
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(ipAddress);
|
||||
dest.writeInt(gateway);
|
||||
dest.writeInt(netmask);
|
||||
dest.writeInt(dns1);
|
||||
dest.writeInt(dns2);
|
||||
dest.writeInt(serverAddress);
|
||||
dest.writeInt(leaseDuration);
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public static final @android.annotation.NonNull Creator<DhcpInfo> CREATOR =
|
||||
new Creator<DhcpInfo>() {
|
||||
public DhcpInfo createFromParcel(Parcel in) {
|
||||
DhcpInfo info = new DhcpInfo();
|
||||
info.ipAddress = in.readInt();
|
||||
info.gateway = in.readInt();
|
||||
info.netmask = in.readInt();
|
||||
info.dns1 = in.readInt();
|
||||
info.dns2 = in.readInt();
|
||||
info.serverAddress = in.readInt();
|
||||
info.leaseDuration = in.readInt();
|
||||
return info;
|
||||
}
|
||||
|
||||
public DhcpInfo[] newArray(int size) {
|
||||
return new DhcpInfo[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
577
framework/src/android/net/DnsResolver.java
Normal file
577
framework/src/android/net/DnsResolver.java
Normal file
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import static android.net.NetworkUtils.getDnsNetwork;
|
||||
import static android.net.NetworkUtils.resNetworkCancel;
|
||||
import static android.net.NetworkUtils.resNetworkQuery;
|
||||
import static android.net.NetworkUtils.resNetworkResult;
|
||||
import static android.net.NetworkUtils.resNetworkSend;
|
||||
import static android.net.util.DnsUtils.haveIpv4;
|
||||
import static android.net.util.DnsUtils.haveIpv6;
|
||||
import static android.net.util.DnsUtils.rfc6724Sort;
|
||||
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
|
||||
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
|
||||
import static android.system.OsConstants.ENONET;
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Looper;
|
||||
import android.os.MessageQueue;
|
||||
import android.system.ErrnoException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.net.module.util.DnsPacket;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Dns resolver class for asynchronous dns querying
|
||||
*
|
||||
* Note that if a client sends a query with more than 1 record in the question section but
|
||||
* the remote dns server does not support this, it may not respond at all, leading to a timeout.
|
||||
*
|
||||
*/
|
||||
public final class DnsResolver {
|
||||
private static final String TAG = "DnsResolver";
|
||||
private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
|
||||
private static final int MAXPACKET = 8 * 1024;
|
||||
private static final int SLEEP_TIME_MS = 2;
|
||||
|
||||
@IntDef(prefix = { "CLASS_" }, value = {
|
||||
CLASS_IN
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface QueryClass {}
|
||||
public static final int CLASS_IN = 1;
|
||||
|
||||
@IntDef(prefix = { "TYPE_" }, value = {
|
||||
TYPE_A,
|
||||
TYPE_AAAA
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface QueryType {}
|
||||
public static final int TYPE_A = 1;
|
||||
public static final int TYPE_AAAA = 28;
|
||||
|
||||
@IntDef(prefix = { "FLAG_" }, value = {
|
||||
FLAG_EMPTY,
|
||||
FLAG_NO_RETRY,
|
||||
FLAG_NO_CACHE_STORE,
|
||||
FLAG_NO_CACHE_LOOKUP
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface QueryFlag {}
|
||||
public static final int FLAG_EMPTY = 0;
|
||||
public static final int FLAG_NO_RETRY = 1 << 0;
|
||||
public static final int FLAG_NO_CACHE_STORE = 1 << 1;
|
||||
public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2;
|
||||
|
||||
@IntDef(prefix = { "ERROR_" }, value = {
|
||||
ERROR_PARSE,
|
||||
ERROR_SYSTEM
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface DnsError {}
|
||||
/**
|
||||
* Indicates that there was an error parsing the response the query.
|
||||
* The cause of this error is available via getCause() and is a {@link ParseException}.
|
||||
*/
|
||||
public static final int ERROR_PARSE = 0;
|
||||
/**
|
||||
* Indicates that there was an error sending the query.
|
||||
* The cause of this error is available via getCause() and is an ErrnoException.
|
||||
*/
|
||||
public static final int ERROR_SYSTEM = 1;
|
||||
|
||||
private static final int NETID_UNSET = 0;
|
||||
|
||||
private static final DnsResolver sInstance = new DnsResolver();
|
||||
|
||||
/**
|
||||
* Get instance for DnsResolver
|
||||
*/
|
||||
public static @NonNull DnsResolver getInstance() {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private DnsResolver() {}
|
||||
|
||||
/**
|
||||
* Base interface for answer callbacks
|
||||
*
|
||||
* @param <T> The type of the answer
|
||||
*/
|
||||
public interface Callback<T> {
|
||||
/**
|
||||
* Success response to
|
||||
* {@link android.net.DnsResolver#query query()} or
|
||||
* {@link android.net.DnsResolver#rawQuery rawQuery()}.
|
||||
*
|
||||
* Invoked when the answer to a query was successfully parsed.
|
||||
*
|
||||
* @param answer <T> answer to the query.
|
||||
* @param rcode The response code in the DNS response.
|
||||
*
|
||||
* {@see android.net.DnsResolver#query query()}
|
||||
*/
|
||||
void onAnswer(@NonNull T answer, int rcode);
|
||||
/**
|
||||
* Error response to
|
||||
* {@link android.net.DnsResolver#query query()} or
|
||||
* {@link android.net.DnsResolver#rawQuery rawQuery()}.
|
||||
*
|
||||
* Invoked when there is no valid answer to
|
||||
* {@link android.net.DnsResolver#query query()}
|
||||
* {@link android.net.DnsResolver#rawQuery rawQuery()}.
|
||||
*
|
||||
* @param error a {@link DnsException} object with additional
|
||||
* detail regarding the failure
|
||||
*/
|
||||
void onError(@NonNull DnsException error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to represent DNS error
|
||||
*/
|
||||
public static class DnsException extends Exception {
|
||||
/**
|
||||
* DNS error code as one of the ERROR_* constants
|
||||
*/
|
||||
@DnsError public final int code;
|
||||
|
||||
DnsException(@DnsError int code, @Nullable Throwable cause) {
|
||||
super(cause);
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a raw DNS query.
|
||||
* The answer will be provided asynchronously through the provided {@link Callback}.
|
||||
*
|
||||
* @param network {@link Network} specifying which network to query on.
|
||||
* {@code null} for query on default network.
|
||||
* @param query blob message to query
|
||||
* @param flags flags as a combination of the FLAGS_* constants
|
||||
* @param executor The {@link Executor} that the callback should be executed on.
|
||||
* @param cancellationSignal used by the caller to signal if the query should be
|
||||
* cancelled. May be {@code null}.
|
||||
* @param callback a {@link Callback} which will be called to notify the caller
|
||||
* of the result of dns query.
|
||||
*/
|
||||
public void rawQuery(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@Nullable CancellationSignal cancellationSignal,
|
||||
@NonNull Callback<? super byte[]> callback) {
|
||||
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
final Object lock = new Object();
|
||||
final FileDescriptor queryfd;
|
||||
try {
|
||||
queryfd = resNetworkSend((network != null)
|
||||
? network.getNetIdForResolv() : NETID_UNSET, query, query.length, flags);
|
||||
} catch (ErrnoException e) {
|
||||
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (lock) {
|
||||
registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
|
||||
if (cancellationSignal == null) return;
|
||||
addCancellationSignal(cancellationSignal, queryfd, lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a DNS query with the specified name, class and query type.
|
||||
* The answer will be provided asynchronously through the provided {@link Callback}.
|
||||
*
|
||||
* @param network {@link Network} specifying which network to query on.
|
||||
* {@code null} for query on default network.
|
||||
* @param domain domain name to query
|
||||
* @param nsClass dns class as one of the CLASS_* constants
|
||||
* @param nsType dns resource record (RR) type as one of the TYPE_* constants
|
||||
* @param flags flags as a combination of the FLAGS_* constants
|
||||
* @param executor The {@link Executor} that the callback should be executed on.
|
||||
* @param cancellationSignal used by the caller to signal if the query should be
|
||||
* cancelled. May be {@code null}.
|
||||
* @param callback a {@link Callback} which will be called to notify the caller
|
||||
* of the result of dns query.
|
||||
*/
|
||||
public void rawQuery(@Nullable Network network, @NonNull String domain,
|
||||
@QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@Nullable CancellationSignal cancellationSignal,
|
||||
@NonNull Callback<? super byte[]> callback) {
|
||||
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
final Object lock = new Object();
|
||||
final FileDescriptor queryfd;
|
||||
try {
|
||||
queryfd = resNetworkQuery((network != null)
|
||||
? network.getNetIdForResolv() : NETID_UNSET, domain, nsClass, nsType, flags);
|
||||
} catch (ErrnoException e) {
|
||||
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
|
||||
return;
|
||||
}
|
||||
synchronized (lock) {
|
||||
registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
|
||||
if (cancellationSignal == null) return;
|
||||
addCancellationSignal(cancellationSignal, queryfd, lock);
|
||||
}
|
||||
}
|
||||
|
||||
private class InetAddressAnswerAccumulator implements Callback<byte[]> {
|
||||
private final List<InetAddress> mAllAnswers;
|
||||
private final Network mNetwork;
|
||||
private int mRcode;
|
||||
private DnsException mDnsException;
|
||||
private final Callback<? super List<InetAddress>> mUserCallback;
|
||||
private final int mTargetAnswerCount;
|
||||
private int mReceivedAnswerCount = 0;
|
||||
|
||||
InetAddressAnswerAccumulator(@NonNull Network network, int size,
|
||||
@NonNull Callback<? super List<InetAddress>> callback) {
|
||||
mNetwork = network;
|
||||
mTargetAnswerCount = size;
|
||||
mAllAnswers = new ArrayList<>();
|
||||
mUserCallback = callback;
|
||||
}
|
||||
|
||||
private boolean maybeReportError() {
|
||||
if (mRcode != 0) {
|
||||
mUserCallback.onAnswer(mAllAnswers, mRcode);
|
||||
return true;
|
||||
}
|
||||
if (mDnsException != null) {
|
||||
mUserCallback.onError(mDnsException);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void maybeReportAnswer() {
|
||||
if (++mReceivedAnswerCount != mTargetAnswerCount) return;
|
||||
if (mAllAnswers.isEmpty() && maybeReportError()) return;
|
||||
mUserCallback.onAnswer(rfc6724Sort(mNetwork, mAllAnswers), mRcode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnswer(@NonNull byte[] answer, int rcode) {
|
||||
// If at least one query succeeded, return an rcode of 0.
|
||||
// Otherwise, arbitrarily return the first rcode received.
|
||||
if (mReceivedAnswerCount == 0 || rcode == 0) {
|
||||
mRcode = rcode;
|
||||
}
|
||||
try {
|
||||
mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses());
|
||||
} catch (DnsPacket.ParseException e) {
|
||||
// Convert the com.android.net.module.util.DnsPacket.ParseException to an
|
||||
// android.net.ParseException. This is the type that was used in Q and is implied
|
||||
// by the public documentation of ERROR_PARSE.
|
||||
//
|
||||
// DnsPacket cannot throw android.net.ParseException directly because it's @hide.
|
||||
ParseException pe = new ParseException(e.reason, e.getCause());
|
||||
pe.setStackTrace(e.getStackTrace());
|
||||
mDnsException = new DnsException(ERROR_PARSE, pe);
|
||||
}
|
||||
maybeReportAnswer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull DnsException error) {
|
||||
mDnsException = error;
|
||||
maybeReportAnswer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a DNS query with the specified name on a network with both IPv4 and IPv6,
|
||||
* get back a set of InetAddresses with rfc6724 sorting style asynchronously.
|
||||
*
|
||||
* This method will examine the connection ability on given network, and query IPv4
|
||||
* and IPv6 if connection is available.
|
||||
*
|
||||
* If at least one query succeeded with valid answer, rcode will be 0
|
||||
*
|
||||
* The answer will be provided asynchronously through the provided {@link Callback}.
|
||||
*
|
||||
* @param network {@link Network} specifying which network to query on.
|
||||
* {@code null} for query on default network.
|
||||
* @param domain domain name to query
|
||||
* @param flags flags as a combination of the FLAGS_* constants
|
||||
* @param executor The {@link Executor} that the callback should be executed on.
|
||||
* @param cancellationSignal used by the caller to signal if the query should be
|
||||
* cancelled. May be {@code null}.
|
||||
* @param callback a {@link Callback} which will be called to notify the
|
||||
* caller of the result of dns query.
|
||||
*/
|
||||
public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@Nullable CancellationSignal cancellationSignal,
|
||||
@NonNull Callback<? super List<InetAddress>> callback) {
|
||||
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
final Object lock = new Object();
|
||||
final Network queryNetwork;
|
||||
try {
|
||||
queryNetwork = (network != null) ? network : getDnsNetwork();
|
||||
} catch (ErrnoException e) {
|
||||
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
|
||||
return;
|
||||
}
|
||||
final boolean queryIpv6 = haveIpv6(queryNetwork);
|
||||
final boolean queryIpv4 = haveIpv4(queryNetwork);
|
||||
|
||||
// This can only happen if queryIpv4 and queryIpv6 are both false.
|
||||
// This almost certainly means that queryNetwork does not exist or no longer exists.
|
||||
if (!queryIpv6 && !queryIpv4) {
|
||||
executor.execute(() -> callback.onError(
|
||||
new DnsException(ERROR_SYSTEM, new ErrnoException("resNetworkQuery", ENONET))));
|
||||
return;
|
||||
}
|
||||
|
||||
final FileDescriptor v4fd;
|
||||
final FileDescriptor v6fd;
|
||||
|
||||
int queryCount = 0;
|
||||
|
||||
if (queryIpv6) {
|
||||
try {
|
||||
v6fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN,
|
||||
TYPE_AAAA, flags);
|
||||
} catch (ErrnoException e) {
|
||||
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
|
||||
return;
|
||||
}
|
||||
queryCount++;
|
||||
} else v6fd = null;
|
||||
|
||||
// Avoiding gateways drop packets if queries are sent too close together
|
||||
try {
|
||||
Thread.sleep(SLEEP_TIME_MS);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
if (queryIpv4) {
|
||||
try {
|
||||
v4fd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, TYPE_A,
|
||||
flags);
|
||||
} catch (ErrnoException e) {
|
||||
if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid.
|
||||
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
|
||||
return;
|
||||
}
|
||||
queryCount++;
|
||||
} else v4fd = null;
|
||||
|
||||
final InetAddressAnswerAccumulator accumulator =
|
||||
new InetAddressAnswerAccumulator(queryNetwork, queryCount, callback);
|
||||
|
||||
synchronized (lock) {
|
||||
if (queryIpv6) {
|
||||
registerFDListener(executor, v6fd, accumulator, cancellationSignal, lock);
|
||||
}
|
||||
if (queryIpv4) {
|
||||
registerFDListener(executor, v4fd, accumulator, cancellationSignal, lock);
|
||||
}
|
||||
if (cancellationSignal == null) return;
|
||||
cancellationSignal.setOnCancelListener(() -> {
|
||||
synchronized (lock) {
|
||||
if (queryIpv4) cancelQuery(v4fd);
|
||||
if (queryIpv6) cancelQuery(v6fd);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a DNS query with the specified name and query type, get back a set of
|
||||
* InetAddresses with rfc6724 sorting style asynchronously.
|
||||
*
|
||||
* The answer will be provided asynchronously through the provided {@link Callback}.
|
||||
*
|
||||
* @param network {@link Network} specifying which network to query on.
|
||||
* {@code null} for query on default network.
|
||||
* @param domain domain name to query
|
||||
* @param nsType dns resource record (RR) type as one of the TYPE_* constants
|
||||
* @param flags flags as a combination of the FLAGS_* constants
|
||||
* @param executor The {@link Executor} that the callback should be executed on.
|
||||
* @param cancellationSignal used by the caller to signal if the query should be
|
||||
* cancelled. May be {@code null}.
|
||||
* @param callback a {@link Callback} which will be called to notify the caller
|
||||
* of the result of dns query.
|
||||
*/
|
||||
public void query(@Nullable Network network, @NonNull String domain,
|
||||
@QueryType int nsType, @QueryFlag int flags,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@Nullable CancellationSignal cancellationSignal,
|
||||
@NonNull Callback<? super List<InetAddress>> callback) {
|
||||
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
final Object lock = new Object();
|
||||
final FileDescriptor queryfd;
|
||||
final Network queryNetwork;
|
||||
try {
|
||||
queryNetwork = (network != null) ? network : getDnsNetwork();
|
||||
queryfd = resNetworkQuery(queryNetwork.getNetIdForResolv(), domain, CLASS_IN, nsType,
|
||||
flags);
|
||||
} catch (ErrnoException e) {
|
||||
executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
|
||||
return;
|
||||
}
|
||||
final InetAddressAnswerAccumulator accumulator =
|
||||
new InetAddressAnswerAccumulator(queryNetwork, 1, callback);
|
||||
synchronized (lock) {
|
||||
registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock);
|
||||
if (cancellationSignal == null) return;
|
||||
addCancellationSignal(cancellationSignal, queryfd, lock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to retrieve DNS response
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final class DnsResponse {
|
||||
public final @NonNull byte[] answerbuf;
|
||||
public final int rcode;
|
||||
public DnsResponse(@NonNull byte[] answerbuf, int rcode) {
|
||||
this.answerbuf = answerbuf;
|
||||
this.rcode = rcode;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerFDListener(@NonNull Executor executor,
|
||||
@NonNull FileDescriptor queryfd, @NonNull Callback<? super byte[]> answerCallback,
|
||||
@Nullable CancellationSignal cancellationSignal, @NonNull Object lock) {
|
||||
final MessageQueue mainThreadMessageQueue = Looper.getMainLooper().getQueue();
|
||||
mainThreadMessageQueue.addOnFileDescriptorEventListener(
|
||||
queryfd,
|
||||
FD_EVENTS,
|
||||
(fd, events) -> {
|
||||
// b/134310704
|
||||
// Unregister fd event listener before resNetworkResult is called to prevent
|
||||
// race condition caused by fd reused.
|
||||
// For example when querying v4 and v6, it's possible that the first query ends
|
||||
// and the fd is closed before the second request starts, which might return
|
||||
// the same fd for the second request. By that time, the looper must have
|
||||
// unregistered the fd, otherwise another event listener can't be registered.
|
||||
mainThreadMessageQueue.removeOnFileDescriptorEventListener(fd);
|
||||
|
||||
executor.execute(() -> {
|
||||
DnsResponse resp = null;
|
||||
ErrnoException exception = null;
|
||||
synchronized (lock) {
|
||||
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
resp = resNetworkResult(fd); // Closes fd, marks it invalid.
|
||||
} catch (ErrnoException e) {
|
||||
Log.e(TAG, "resNetworkResult:" + e.toString());
|
||||
exception = e;
|
||||
}
|
||||
}
|
||||
if (exception != null) {
|
||||
answerCallback.onError(new DnsException(ERROR_SYSTEM, exception));
|
||||
return;
|
||||
}
|
||||
answerCallback.onAnswer(resp.answerbuf, resp.rcode);
|
||||
});
|
||||
|
||||
// The file descriptor has already been unregistered, so it does not really
|
||||
// matter what is returned here. In spirit 0 (meaning "unregister this FD")
|
||||
// is still the closest to what the looper needs to do. When returning 0,
|
||||
// Looper knows to ignore the fd if it has already been unregistered.
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
private void cancelQuery(@NonNull FileDescriptor queryfd) {
|
||||
if (!queryfd.valid()) return;
|
||||
Looper.getMainLooper().getQueue().removeOnFileDescriptorEventListener(queryfd);
|
||||
resNetworkCancel(queryfd); // Closes fd, marks it invalid.
|
||||
}
|
||||
|
||||
private void addCancellationSignal(@NonNull CancellationSignal cancellationSignal,
|
||||
@NonNull FileDescriptor queryfd, @NonNull Object lock) {
|
||||
cancellationSignal.setOnCancelListener(() -> {
|
||||
synchronized (lock) {
|
||||
cancelQuery(queryfd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class DnsAddressAnswer extends DnsPacket {
|
||||
private static final String TAG = "DnsResolver.DnsAddressAnswer";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
private final int mQueryType;
|
||||
|
||||
DnsAddressAnswer(@NonNull byte[] data) throws ParseException {
|
||||
super(data);
|
||||
if ((mHeader.flags & (1 << 15)) == 0) {
|
||||
throw new ParseException("Not an answer packet");
|
||||
}
|
||||
if (mHeader.getRecordCount(QDSECTION) == 0) {
|
||||
throw new ParseException("No question found");
|
||||
}
|
||||
// Expect only one question in question section.
|
||||
mQueryType = mRecords[QDSECTION].get(0).nsType;
|
||||
}
|
||||
|
||||
public @NonNull List<InetAddress> getAddresses() {
|
||||
final List<InetAddress> results = new ArrayList<InetAddress>();
|
||||
if (mHeader.getRecordCount(ANSECTION) == 0) return results;
|
||||
|
||||
for (final DnsRecord ansSec : mRecords[ANSECTION]) {
|
||||
// Only support A and AAAA, also ignore answers if query type != answer type.
|
||||
int nsType = ansSec.nsType;
|
||||
if (nsType != mQueryType || (nsType != TYPE_A && nsType != TYPE_AAAA)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
results.add(InetAddress.getByAddress(ansSec.getRR()));
|
||||
} catch (UnknownHostException e) {
|
||||
if (DBG) {
|
||||
Log.w(TAG, "rr to address fail");
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
27
framework/src/android/net/ICaptivePortal.aidl
Normal file
27
framework/src/android/net/ICaptivePortal.aidl
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2015, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
/**
|
||||
* Interface to inform NetworkMonitor of decisions of app handling captive portal.
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ICaptivePortal {
|
||||
void appRequest(int request);
|
||||
void appResponse(int response);
|
||||
void logEvent(int eventId, String packageName);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.net.ConnectivityDiagnosticsManager;
|
||||
import android.net.Network;
|
||||
|
||||
/** @hide */
|
||||
oneway interface IConnectivityDiagnosticsCallback {
|
||||
void onConnectivityReportAvailable(in ConnectivityDiagnosticsManager.ConnectivityReport report);
|
||||
void onDataStallSuspected(in ConnectivityDiagnosticsManager.DataStallReport report);
|
||||
void onNetworkConnectivityReported(in Network n, boolean hasConnectivity);
|
||||
}
|
||||
246
framework/src/android/net/IConnectivityManager.aidl
Normal file
246
framework/src/android/net/IConnectivityManager.aidl
Normal file
@@ -0,0 +1,246 @@
|
||||
/**
|
||||
* Copyright (c) 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.net.ConnectionInfo;
|
||||
import android.net.ConnectivityDiagnosticsManager;
|
||||
import android.net.IConnectivityDiagnosticsCallback;
|
||||
import android.net.IQosCallback;
|
||||
import android.net.ISocketKeepaliveCallback;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkAgentConfig;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.NetworkState;
|
||||
import android.net.ProxyInfo;
|
||||
import android.net.UidRange;
|
||||
import android.net.QosSocketInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.INetworkActivityListener;
|
||||
import android.os.Messenger;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.ResultReceiver;
|
||||
|
||||
import com.android.connectivity.aidl.INetworkAgent;
|
||||
import com.android.internal.net.LegacyVpnInfo;
|
||||
import com.android.internal.net.VpnConfig;
|
||||
import com.android.internal.net.VpnProfile;
|
||||
|
||||
/**
|
||||
* Interface that answers queries about, and allows changing, the
|
||||
* state of network connectivity.
|
||||
*/
|
||||
/** {@hide} */
|
||||
interface IConnectivityManager
|
||||
{
|
||||
Network getActiveNetwork();
|
||||
Network getActiveNetworkForUid(int uid, boolean ignoreBlocked);
|
||||
@UnsupportedAppUsage
|
||||
NetworkInfo getActiveNetworkInfo();
|
||||
NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked);
|
||||
@UnsupportedAppUsage(maxTargetSdk = 28)
|
||||
NetworkInfo getNetworkInfo(int networkType);
|
||||
NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked);
|
||||
@UnsupportedAppUsage
|
||||
NetworkInfo[] getAllNetworkInfo();
|
||||
Network getNetworkForType(int networkType);
|
||||
Network[] getAllNetworks();
|
||||
NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(
|
||||
int userId, String callingPackageName);
|
||||
|
||||
boolean isNetworkSupported(int networkType);
|
||||
|
||||
@UnsupportedAppUsage
|
||||
LinkProperties getActiveLinkProperties();
|
||||
LinkProperties getLinkPropertiesForType(int networkType);
|
||||
LinkProperties getLinkProperties(in Network network);
|
||||
|
||||
NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
|
||||
NetworkState[] getAllNetworkState();
|
||||
|
||||
boolean isActiveNetworkMetered();
|
||||
|
||||
boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress,
|
||||
String callingPackageName, String callingAttributionTag);
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = 29,
|
||||
publicAlternatives = "Use {@code TetheringManager#getLastTetherError} as alternative")
|
||||
int getLastTetherError(String iface);
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = 29,
|
||||
publicAlternatives = "Use {@code TetheringManager#getTetherableIfaces} as alternative")
|
||||
String[] getTetherableIfaces();
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = 29,
|
||||
publicAlternatives = "Use {@code TetheringManager#getTetheredIfaces} as alternative")
|
||||
String[] getTetheredIfaces();
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = 29,
|
||||
publicAlternatives = "Use {@code TetheringManager#getTetheringErroredIfaces} "
|
||||
+ "as Alternative")
|
||||
String[] getTetheringErroredIfaces();
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = 29,
|
||||
publicAlternatives = "Use {@code TetheringManager#getTetherableUsbRegexs} as alternative")
|
||||
String[] getTetherableUsbRegexs();
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = 29,
|
||||
publicAlternatives = "Use {@code TetheringManager#getTetherableWifiRegexs} as alternative")
|
||||
String[] getTetherableWifiRegexs();
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = 28)
|
||||
void reportInetCondition(int networkType, int percentage);
|
||||
|
||||
void reportNetworkConnectivity(in Network network, boolean hasConnectivity);
|
||||
|
||||
ProxyInfo getGlobalProxy();
|
||||
|
||||
void setGlobalProxy(in ProxyInfo p);
|
||||
|
||||
ProxyInfo getProxyForNetwork(in Network nework);
|
||||
|
||||
boolean prepareVpn(String oldPackage, String newPackage, int userId);
|
||||
|
||||
void setVpnPackageAuthorization(String packageName, int userId, int vpnType);
|
||||
|
||||
ParcelFileDescriptor establishVpn(in VpnConfig config);
|
||||
|
||||
boolean provisionVpnProfile(in VpnProfile profile, String packageName);
|
||||
|
||||
void deleteVpnProfile(String packageName);
|
||||
|
||||
void startVpnProfile(String packageName);
|
||||
|
||||
void stopVpnProfile(String packageName);
|
||||
|
||||
VpnConfig getVpnConfig(int userId);
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
|
||||
void startLegacyVpn(in VpnProfile profile);
|
||||
|
||||
LegacyVpnInfo getLegacyVpnInfo(int userId);
|
||||
|
||||
boolean updateLockdownVpn();
|
||||
boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
|
||||
boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown,
|
||||
in List<String> lockdownWhitelist);
|
||||
String getAlwaysOnVpnPackage(int userId);
|
||||
boolean isVpnLockdownEnabled(int userId);
|
||||
List<String> getVpnLockdownWhitelist(int userId);
|
||||
void setRequireVpnForUids(boolean requireVpn, in UidRange[] ranges);
|
||||
|
||||
void setProvisioningNotificationVisible(boolean visible, int networkType, in String action);
|
||||
|
||||
void setAirplaneMode(boolean enable);
|
||||
|
||||
boolean requestBandwidthUpdate(in Network network);
|
||||
|
||||
int registerNetworkFactory(in Messenger messenger, in String name);
|
||||
void unregisterNetworkFactory(in Messenger messenger);
|
||||
|
||||
int registerNetworkProvider(in Messenger messenger, in String name);
|
||||
void unregisterNetworkProvider(in Messenger messenger);
|
||||
|
||||
void declareNetworkRequestUnfulfillable(in NetworkRequest request);
|
||||
|
||||
Network registerNetworkAgent(in INetworkAgent na, in NetworkInfo ni, in LinkProperties lp,
|
||||
in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
|
||||
in int factorySerialNumber);
|
||||
|
||||
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType,
|
||||
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
|
||||
String callingPackageName, String callingAttributionTag);
|
||||
|
||||
NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities,
|
||||
in PendingIntent operation, String callingPackageName, String callingAttributionTag);
|
||||
|
||||
void releasePendingNetworkRequest(in PendingIntent operation);
|
||||
|
||||
NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities,
|
||||
in Messenger messenger, in IBinder binder, String callingPackageName);
|
||||
|
||||
void pendingListenForNetwork(in NetworkCapabilities networkCapabilities,
|
||||
in PendingIntent operation, String callingPackageName);
|
||||
|
||||
void releaseNetworkRequest(in NetworkRequest networkRequest);
|
||||
|
||||
void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
|
||||
void setAcceptPartialConnectivity(in Network network, boolean accept, boolean always);
|
||||
void setAvoidUnvalidated(in Network network);
|
||||
void startCaptivePortalApp(in Network network);
|
||||
void startCaptivePortalAppInternal(in Network network, in Bundle appExtras);
|
||||
|
||||
boolean shouldAvoidBadWifi();
|
||||
int getMultipathPreference(in Network Network);
|
||||
|
||||
NetworkRequest getDefaultRequest();
|
||||
|
||||
int getRestoreDefaultNetworkDelay(int networkType);
|
||||
|
||||
boolean addVpnAddress(String address, int prefixLength);
|
||||
boolean removeVpnAddress(String address, int prefixLength);
|
||||
boolean setUnderlyingNetworksForVpn(in Network[] networks);
|
||||
|
||||
void factoryReset();
|
||||
|
||||
void startNattKeepalive(in Network network, int intervalSeconds,
|
||||
in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr);
|
||||
|
||||
void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId,
|
||||
int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
|
||||
String dstAddr);
|
||||
|
||||
void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds,
|
||||
in ISocketKeepaliveCallback cb);
|
||||
|
||||
void stopKeepalive(in Network network, int slot);
|
||||
|
||||
String getCaptivePortalServerUrl();
|
||||
|
||||
byte[] getNetworkWatchlistConfigHash();
|
||||
|
||||
int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
|
||||
boolean isCallerCurrentAlwaysOnVpnApp();
|
||||
boolean isCallerCurrentAlwaysOnVpnLockdownApp();
|
||||
|
||||
void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback,
|
||||
in NetworkRequest request, String callingPackageName);
|
||||
void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback);
|
||||
|
||||
IBinder startOrGetTestNetworkService();
|
||||
|
||||
void simulateDataStall(int detectionMethod, long timestampMillis, in Network network,
|
||||
in PersistableBundle extras);
|
||||
|
||||
void systemReady();
|
||||
|
||||
void registerNetworkActivityListener(in INetworkActivityListener l);
|
||||
|
||||
void unregisterNetworkActivityListener(in INetworkActivityListener l);
|
||||
|
||||
boolean isDefaultNetworkActive();
|
||||
|
||||
void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
|
||||
void unregisterQosCallback(in IQosCallback callback);
|
||||
}
|
||||
34
framework/src/android/net/ISocketKeepaliveCallback.aidl
Normal file
34
framework/src/android/net/ISocketKeepaliveCallback.aidl
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2019, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
/**
|
||||
* Callback to provide status changes of keepalive offload.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface ISocketKeepaliveCallback
|
||||
{
|
||||
/** The keepalive was successfully started. */
|
||||
void onStarted(int slot);
|
||||
/** The keepalive was successfully stopped. */
|
||||
void onStopped();
|
||||
/** The keepalive was stopped because of an error. */
|
||||
void onError(int error);
|
||||
/** The keepalive on a TCP socket was stopped because the socket received data. */
|
||||
void onDataReceived();
|
||||
}
|
||||
39
framework/src/android/net/ITestNetworkManager.aidl
Normal file
39
framework/src/android/net/ITestNetworkManager.aidl
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2018, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.net.LinkAddress;
|
||||
import android.net.LinkProperties;
|
||||
import android.net.TestNetworkInterface;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
/**
|
||||
* Interface that allows for creation and management of test-only networks.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
interface ITestNetworkManager
|
||||
{
|
||||
TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs);
|
||||
TestNetworkInterface createTapInterface();
|
||||
|
||||
void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered,
|
||||
in int[] administratorUids, in IBinder binder);
|
||||
|
||||
void teardownTestNetwork(int netId);
|
||||
}
|
||||
65
framework/src/android/net/InetAddresses.java
Normal file
65
framework/src/android/net/InetAddresses.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import libcore.net.InetAddressUtils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* Utility methods for {@link InetAddress} implementations.
|
||||
*/
|
||||
public class InetAddresses {
|
||||
|
||||
private InetAddresses() {}
|
||||
|
||||
/**
|
||||
* Checks to see if the {@code address} is a numeric address (such as {@code "192.0.2.1"} or
|
||||
* {@code "2001:db8::1:2"}).
|
||||
*
|
||||
* <p>A numeric address is either an IPv4 address containing exactly 4 decimal numbers or an
|
||||
* IPv6 numeric address. IPv4 addresses that consist of either hexadecimal or octal digits or
|
||||
* do not have exactly 4 numbers are not treated as numeric.
|
||||
*
|
||||
* <p>This method will never do a DNS lookup.
|
||||
*
|
||||
* @param address the address to parse.
|
||||
* @return true if the supplied address is numeric, false otherwise.
|
||||
*/
|
||||
public static boolean isNumericAddress(@NonNull String address) {
|
||||
return InetAddressUtils.isNumericAddress(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InetAddress corresponding to the given numeric address (such
|
||||
* as {@code "192.168.0.1"} or {@code "2001:4860:800d::68"}).
|
||||
*
|
||||
* <p>See {@link #isNumericAddress(String)} (String)} for a definition as to what constitutes a
|
||||
* numeric address.
|
||||
*
|
||||
* <p>This method will never do a DNS lookup.
|
||||
*
|
||||
* @param address the address to parse, must be numeric.
|
||||
* @return an {@link InetAddress} instance corresponding to the address.
|
||||
* @throws IllegalArgumentException if {@code address} is not a numeric address.
|
||||
*/
|
||||
public static @NonNull InetAddress parseNumericAddress(@NonNull String address) {
|
||||
return InetAddressUtils.parseNumericAddress(address);
|
||||
}
|
||||
}
|
||||
19
framework/src/android/net/InterfaceConfiguration.aidl
Normal file
19
framework/src/android/net/InterfaceConfiguration.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
parcelable InterfaceConfiguration;
|
||||
66
framework/src/android/net/InvalidPacketException.java
Normal file
66
framework/src/android/net/InvalidPacketException.java
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.SystemApi;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Thrown when a packet is invalid.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class InvalidPacketException extends Exception {
|
||||
private final int mError;
|
||||
|
||||
// Must match SocketKeepalive#ERROR_INVALID_IP_ADDRESS.
|
||||
/** Invalid IP address. */
|
||||
public static final int ERROR_INVALID_IP_ADDRESS = -21;
|
||||
|
||||
// Must match SocketKeepalive#ERROR_INVALID_PORT.
|
||||
/** Invalid port number. */
|
||||
public static final int ERROR_INVALID_PORT = -22;
|
||||
|
||||
// Must match SocketKeepalive#ERROR_INVALID_LENGTH.
|
||||
/** Invalid packet length. */
|
||||
public static final int ERROR_INVALID_LENGTH = -23;
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = { "ERROR_" }, value = {
|
||||
ERROR_INVALID_IP_ADDRESS,
|
||||
ERROR_INVALID_PORT,
|
||||
ERROR_INVALID_LENGTH
|
||||
})
|
||||
public @interface ErrorCode {}
|
||||
|
||||
/**
|
||||
* This packet is invalid.
|
||||
* See the error code for details.
|
||||
*/
|
||||
public InvalidPacketException(@ErrorCode final int error) {
|
||||
this.mError = error;
|
||||
}
|
||||
|
||||
/** Get error code. */
|
||||
public int getError() {
|
||||
return mError;
|
||||
}
|
||||
}
|
||||
19
framework/src/android/net/IpConfiguration.aidl
Normal file
19
framework/src/android/net/IpConfiguration.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
parcelable IpConfiguration;
|
||||
223
framework/src/android/net/IpConfiguration.java
Normal file
223
framework/src/android/net/IpConfiguration.java
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.SystemApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A class representing a configured network.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class IpConfiguration implements Parcelable {
|
||||
private static final String TAG = "IpConfiguration";
|
||||
|
||||
// This enum has been used by apps through reflection for many releases.
|
||||
// Therefore they can't just be removed. Duplicating these constants to
|
||||
// give an alternate SystemApi is a worse option than exposing them.
|
||||
@SuppressLint("Enum")
|
||||
public enum IpAssignment {
|
||||
/* Use statically configured IP settings. Configuration can be accessed
|
||||
* with staticIpConfiguration */
|
||||
STATIC,
|
||||
/* Use dynamically configured IP settings */
|
||||
DHCP,
|
||||
/* no IP details are assigned, this is used to indicate
|
||||
* that any existing IP settings should be retained */
|
||||
UNASSIGNED
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public IpAssignment ipAssignment;
|
||||
|
||||
/** @hide */
|
||||
public StaticIpConfiguration staticIpConfiguration;
|
||||
|
||||
// This enum has been used by apps through reflection for many releases.
|
||||
// Therefore they can't just be removed. Duplicating these constants to
|
||||
// give an alternate SystemApi is a worse option than exposing them.
|
||||
@SuppressLint("Enum")
|
||||
public enum ProxySettings {
|
||||
/* No proxy is to be used. Any existing proxy settings
|
||||
* should be cleared. */
|
||||
NONE,
|
||||
/* Use statically configured proxy. Configuration can be accessed
|
||||
* with httpProxy. */
|
||||
STATIC,
|
||||
/* no proxy details are assigned, this is used to indicate
|
||||
* that any existing proxy settings should be retained */
|
||||
UNASSIGNED,
|
||||
/* Use a Pac based proxy.
|
||||
*/
|
||||
PAC
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public ProxySettings proxySettings;
|
||||
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage
|
||||
public ProxyInfo httpProxy;
|
||||
|
||||
private void init(IpAssignment ipAssignment,
|
||||
ProxySettings proxySettings,
|
||||
StaticIpConfiguration staticIpConfiguration,
|
||||
ProxyInfo httpProxy) {
|
||||
this.ipAssignment = ipAssignment;
|
||||
this.proxySettings = proxySettings;
|
||||
this.staticIpConfiguration = (staticIpConfiguration == null) ?
|
||||
null : new StaticIpConfiguration(staticIpConfiguration);
|
||||
this.httpProxy = (httpProxy == null) ?
|
||||
null : new ProxyInfo(httpProxy);
|
||||
}
|
||||
|
||||
public IpConfiguration() {
|
||||
init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public IpConfiguration(IpAssignment ipAssignment,
|
||||
ProxySettings proxySettings,
|
||||
StaticIpConfiguration staticIpConfiguration,
|
||||
ProxyInfo httpProxy) {
|
||||
init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy);
|
||||
}
|
||||
|
||||
public IpConfiguration(@NonNull IpConfiguration source) {
|
||||
this();
|
||||
if (source != null) {
|
||||
init(source.ipAssignment, source.proxySettings,
|
||||
source.staticIpConfiguration, source.httpProxy);
|
||||
}
|
||||
}
|
||||
|
||||
public @NonNull IpAssignment getIpAssignment() {
|
||||
return ipAssignment;
|
||||
}
|
||||
|
||||
public void setIpAssignment(@NonNull IpAssignment ipAssignment) {
|
||||
this.ipAssignment = ipAssignment;
|
||||
}
|
||||
|
||||
public @Nullable StaticIpConfiguration getStaticIpConfiguration() {
|
||||
return staticIpConfiguration;
|
||||
}
|
||||
|
||||
public void setStaticIpConfiguration(@Nullable StaticIpConfiguration staticIpConfiguration) {
|
||||
this.staticIpConfiguration = staticIpConfiguration;
|
||||
}
|
||||
|
||||
public @NonNull ProxySettings getProxySettings() {
|
||||
return proxySettings;
|
||||
}
|
||||
|
||||
public void setProxySettings(@NonNull ProxySettings proxySettings) {
|
||||
this.proxySettings = proxySettings;
|
||||
}
|
||||
|
||||
public @Nullable ProxyInfo getHttpProxy() {
|
||||
return httpProxy;
|
||||
}
|
||||
|
||||
public void setHttpProxy(@Nullable ProxyInfo httpProxy) {
|
||||
this.httpProxy = httpProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sbuf = new StringBuilder();
|
||||
sbuf.append("IP assignment: " + ipAssignment.toString());
|
||||
sbuf.append("\n");
|
||||
if (staticIpConfiguration != null) {
|
||||
sbuf.append("Static configuration: " + staticIpConfiguration.toString());
|
||||
sbuf.append("\n");
|
||||
}
|
||||
sbuf.append("Proxy settings: " + proxySettings.toString());
|
||||
sbuf.append("\n");
|
||||
if (httpProxy != null) {
|
||||
sbuf.append("HTTP proxy: " + httpProxy.toString());
|
||||
sbuf.append("\n");
|
||||
}
|
||||
|
||||
return sbuf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof IpConfiguration)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IpConfiguration other = (IpConfiguration) o;
|
||||
return this.ipAssignment == other.ipAssignment &&
|
||||
this.proxySettings == other.proxySettings &&
|
||||
Objects.equals(this.staticIpConfiguration, other.staticIpConfiguration) &&
|
||||
Objects.equals(this.httpProxy, other.httpProxy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 13 + (staticIpConfiguration != null ? staticIpConfiguration.hashCode() : 0) +
|
||||
17 * ipAssignment.ordinal() +
|
||||
47 * proxySettings.ordinal() +
|
||||
83 * httpProxy.hashCode();
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString(ipAssignment.name());
|
||||
dest.writeString(proxySettings.name());
|
||||
dest.writeParcelable(staticIpConfiguration, flags);
|
||||
dest.writeParcelable(httpProxy, flags);
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public static final @NonNull Creator<IpConfiguration> CREATOR =
|
||||
new Creator<IpConfiguration>() {
|
||||
public IpConfiguration createFromParcel(Parcel in) {
|
||||
IpConfiguration config = new IpConfiguration();
|
||||
config.ipAssignment = IpAssignment.valueOf(in.readString());
|
||||
config.proxySettings = ProxySettings.valueOf(in.readString());
|
||||
config.staticIpConfiguration = in.readParcelable(null);
|
||||
config.httpProxy = in.readParcelable(null);
|
||||
return config;
|
||||
}
|
||||
|
||||
public IpConfiguration[] newArray(int size) {
|
||||
return new IpConfiguration[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
22
framework/src/android/net/IpPrefix.aidl
Normal file
22
framework/src/android/net/IpPrefix.aidl
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface
|
||||
// build rule). IpPrefix is also used in cpp but only as non-stable aidl.
|
||||
@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h";
|
||||
300
framework/src/android/net/IpPrefix.java
Normal file
300
framework/src/android/net/IpPrefix.java
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a
|
||||
* power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of
|
||||
* information:
|
||||
*
|
||||
* <ul>
|
||||
* <li>A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix.
|
||||
* <li>A prefix length. This specifies the length of the prefix by specifing the number of bits
|
||||
* in the IP address, starting from the most significant bit in network byte order, that
|
||||
* are constant for all addresses in the prefix.
|
||||
* </ul>
|
||||
*
|
||||
* For example, the prefix <code>192.0.2.0/24</code> covers the 256 IPv4 addresses from
|
||||
* <code>192.0.2.0</code> to <code>192.0.2.255</code>, inclusive, and the prefix
|
||||
* <code>2001:db8:1:2</code> covers the 2^64 IPv6 addresses from <code>2001:db8:1:2::</code> to
|
||||
* <code>2001:db8:1:2:ffff:ffff:ffff:ffff</code>, inclusive.
|
||||
*
|
||||
* Objects of this class are immutable.
|
||||
*/
|
||||
public final class IpPrefix implements Parcelable {
|
||||
private final byte[] address; // network byte order
|
||||
private final int prefixLength;
|
||||
|
||||
private void checkAndMaskAddressAndPrefixLength() {
|
||||
if (address.length != 4 && address.length != 16) {
|
||||
throw new IllegalArgumentException(
|
||||
"IpPrefix has " + address.length + " bytes which is neither 4 nor 16");
|
||||
}
|
||||
NetworkUtils.maskRawAddress(address, prefixLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in
|
||||
* network byte order and a prefix length. Silently truncates the address to the prefix length,
|
||||
* so for example {@code 192.0.2.1/24} is silently converted to {@code 192.0.2.0/24}.
|
||||
*
|
||||
* @param address the IP address. Must be non-null and exactly 4 or 16 bytes long.
|
||||
* @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public IpPrefix(@NonNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength) {
|
||||
this.address = address.clone();
|
||||
this.prefixLength = prefixLength;
|
||||
checkAndMaskAddressAndPrefixLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IpPrefix} from an IPv4 or IPv6 address and a prefix length. Silently
|
||||
* truncates the address to the prefix length, so for example {@code 192.0.2.1/24} is silently
|
||||
* converted to {@code 192.0.2.0/24}.
|
||||
*
|
||||
* @param address the IP address. Must be non-null.
|
||||
* @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) {
|
||||
// We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
|
||||
// which is unnecessary because getAddress() already returns a clone.
|
||||
this.address = address.getAddress();
|
||||
this.prefixLength = prefixLength;
|
||||
checkAndMaskAddressAndPrefixLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new IpPrefix from a string such as "192.0.2.1/24" or "2001:db8::1/64".
|
||||
* Silently truncates the address to the prefix length, so for example {@code 192.0.2.1/24}
|
||||
* is silently converted to {@code 192.0.2.0/24}.
|
||||
*
|
||||
* @param prefix the prefix to parse
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public IpPrefix(@NonNull String prefix) {
|
||||
// We don't reuse the (InetAddress, int) constructor because "error: call to this must be
|
||||
// first statement in constructor". We could factor out setting the member variables to an
|
||||
// init() method, but if we did, then we'd have to make the members non-final, or "error:
|
||||
// cannot assign a value to final variable address". So we just duplicate the code here.
|
||||
Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(prefix);
|
||||
this.address = ipAndMask.first.getAddress();
|
||||
this.prefixLength = ipAndMask.second;
|
||||
checkAndMaskAddressAndPrefixLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two
|
||||
* objects are equal if they have the same startAddress and prefixLength.
|
||||
*
|
||||
* @param obj the object to be tested for equality.
|
||||
* @return {@code true} if both objects are equal, {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof IpPrefix)) {
|
||||
return false;
|
||||
}
|
||||
IpPrefix that = (IpPrefix) obj;
|
||||
return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hashcode of the represented IP prefix.
|
||||
*
|
||||
* @return the appropriate hashcode value.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(address) + 11 * prefixLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the first IP address in the prefix. Modifying the returned object does not
|
||||
* change this object's contents.
|
||||
*
|
||||
* @return the address in the form of a byte array.
|
||||
*/
|
||||
public @NonNull InetAddress getAddress() {
|
||||
try {
|
||||
return InetAddress.getByAddress(address);
|
||||
} catch (UnknownHostException e) {
|
||||
// Cannot happen. InetAddress.getByAddress can only throw an exception if the byte
|
||||
// array is the wrong length, but we check that in the constructor.
|
||||
throw new IllegalArgumentException("Address is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth
|
||||
* element). Modifying the returned array does not change this object's contents.
|
||||
*
|
||||
* @return the address in the form of a byte array.
|
||||
*/
|
||||
public @NonNull byte[] getRawAddress() {
|
||||
return address.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prefix length of this {@code IpPrefix}.
|
||||
*
|
||||
* @return the prefix length.
|
||||
*/
|
||||
@IntRange(from = 0, to = 128)
|
||||
public int getPrefixLength() {
|
||||
return prefixLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the prefix contains the specified address.
|
||||
*
|
||||
* @param address An {@link InetAddress} to test.
|
||||
* @return {@code true} if the prefix covers the given address. {@code false} otherwise.
|
||||
*/
|
||||
public boolean contains(@NonNull InetAddress address) {
|
||||
byte[] addrBytes = address.getAddress();
|
||||
if (addrBytes == null || addrBytes.length != this.address.length) {
|
||||
return false;
|
||||
}
|
||||
NetworkUtils.maskRawAddress(addrBytes, prefixLength);
|
||||
return Arrays.equals(this.address, addrBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified prefix is entirely contained in this prefix.
|
||||
*
|
||||
* Note this is mathematical inclusion, so a prefix is always contained within itself.
|
||||
* @param otherPrefix the prefix to test
|
||||
* @hide
|
||||
*/
|
||||
public boolean containsPrefix(@NonNull IpPrefix otherPrefix) {
|
||||
if (otherPrefix.getPrefixLength() < prefixLength) return false;
|
||||
final byte[] otherAddress = otherPrefix.getRawAddress();
|
||||
NetworkUtils.maskRawAddress(otherAddress, prefixLength);
|
||||
return Arrays.equals(otherAddress, address);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean isIPv6() {
|
||||
return getAddress() instanceof Inet6Address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean isIPv4() {
|
||||
return getAddress() instanceof Inet4Address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this {@code IpPrefix}.
|
||||
*
|
||||
* @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}.
|
||||
*/
|
||||
public String toString() {
|
||||
try {
|
||||
return InetAddress.getByAddress(address).getHostAddress() + "/" + prefixLength;
|
||||
} catch(UnknownHostException e) {
|
||||
// Cosmic rays?
|
||||
throw new IllegalStateException("IpPrefix with invalid address! Shouldn't happen.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface.
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface.
|
||||
*/
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeByteArray(address);
|
||||
dest.writeInt(prefixLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a comparator ordering IpPrefixes by length, shorter to longer.
|
||||
* Contents of the address will break ties.
|
||||
* @hide
|
||||
*/
|
||||
public static Comparator<IpPrefix> lengthComparator() {
|
||||
return new Comparator<IpPrefix>() {
|
||||
@Override
|
||||
public int compare(IpPrefix prefix1, IpPrefix prefix2) {
|
||||
if (prefix1.isIPv4()) {
|
||||
if (prefix2.isIPv6()) return -1;
|
||||
} else {
|
||||
if (prefix2.isIPv4()) return 1;
|
||||
}
|
||||
final int p1len = prefix1.getPrefixLength();
|
||||
final int p2len = prefix2.getPrefixLength();
|
||||
if (p1len < p2len) return -1;
|
||||
if (p2len < p1len) return 1;
|
||||
final byte[] a1 = prefix1.address;
|
||||
final byte[] a2 = prefix2.address;
|
||||
final int len = a1.length < a2.length ? a1.length : a2.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (a1[i] < a2[i]) return -1;
|
||||
if (a1[i] > a2[i]) return 1;
|
||||
}
|
||||
if (a2.length < len) return 1;
|
||||
if (a1.length < len) return -1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface.
|
||||
*/
|
||||
public static final @android.annotation.NonNull Creator<IpPrefix> CREATOR =
|
||||
new Creator<IpPrefix>() {
|
||||
public IpPrefix createFromParcel(Parcel in) {
|
||||
byte[] address = in.createByteArray();
|
||||
int prefixLength = in.readInt();
|
||||
return new IpPrefix(address, prefixLength);
|
||||
}
|
||||
|
||||
public IpPrefix[] newArray(int size) {
|
||||
return new IpPrefix[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
19
framework/src/android/net/KeepalivePacketData.aidl
Normal file
19
framework/src/android/net/KeepalivePacketData.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
parcelable KeepalivePacketData;
|
||||
119
framework/src/android/net/KeepalivePacketData.java
Normal file
119
framework/src/android/net/KeepalivePacketData.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
|
||||
import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.net.module.util.IpUtils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* Represents the actual packets that are sent by the
|
||||
* {@link android.net.SocketKeepalive} API.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public class KeepalivePacketData {
|
||||
private static final String TAG = "KeepalivePacketData";
|
||||
|
||||
/** Source IP address */
|
||||
@NonNull
|
||||
private final InetAddress mSrcAddress;
|
||||
|
||||
/** Destination IP address */
|
||||
@NonNull
|
||||
private final InetAddress mDstAddress;
|
||||
|
||||
/** Source port */
|
||||
private final int mSrcPort;
|
||||
|
||||
/** Destination port */
|
||||
private final int mDstPort;
|
||||
|
||||
/** Packet data. A raw byte string of packet data, not including the link-layer header. */
|
||||
private final byte[] mPacket;
|
||||
|
||||
// Note: If you add new fields, please modify the parcelling code in the child classes.
|
||||
|
||||
|
||||
// This should only be constructed via static factory methods, such as
|
||||
// nattKeepalivePacket.
|
||||
/**
|
||||
* A holding class for data necessary to build a keepalive packet.
|
||||
*/
|
||||
protected KeepalivePacketData(@NonNull InetAddress srcAddress,
|
||||
@IntRange(from = 0, to = 65535) int srcPort, @NonNull InetAddress dstAddress,
|
||||
@IntRange(from = 0, to = 65535) int dstPort,
|
||||
@NonNull byte[] data) throws InvalidPacketException {
|
||||
this.mSrcAddress = srcAddress;
|
||||
this.mDstAddress = dstAddress;
|
||||
this.mSrcPort = srcPort;
|
||||
this.mDstPort = dstPort;
|
||||
this.mPacket = data;
|
||||
|
||||
// Check we have two IP addresses of the same family.
|
||||
if (srcAddress == null || dstAddress == null || !srcAddress.getClass().getName()
|
||||
.equals(dstAddress.getClass().getName())) {
|
||||
Log.e(TAG, "Invalid or mismatched InetAddresses in KeepalivePacketData");
|
||||
throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
|
||||
}
|
||||
|
||||
// Check the ports.
|
||||
if (!IpUtils.isValidUdpOrTcpPort(srcPort) || !IpUtils.isValidUdpOrTcpPort(dstPort)) {
|
||||
Log.e(TAG, "Invalid ports in KeepalivePacketData");
|
||||
throw new InvalidPacketException(ERROR_INVALID_PORT);
|
||||
}
|
||||
}
|
||||
|
||||
/** Get source IP address. */
|
||||
@NonNull
|
||||
public InetAddress getSrcAddress() {
|
||||
return mSrcAddress;
|
||||
}
|
||||
|
||||
/** Get destination IP address. */
|
||||
@NonNull
|
||||
public InetAddress getDstAddress() {
|
||||
return mDstAddress;
|
||||
}
|
||||
|
||||
/** Get source port number. */
|
||||
public int getSrcPort() {
|
||||
return mSrcPort;
|
||||
}
|
||||
|
||||
/** Get destination port number. */
|
||||
public int getDstPort() {
|
||||
return mDstPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array of the given packet data.
|
||||
*/
|
||||
@NonNull
|
||||
public byte[] getPacket() {
|
||||
return mPacket.clone();
|
||||
}
|
||||
|
||||
}
|
||||
21
framework/src/android/net/LinkAddress.aidl
Normal file
21
framework/src/android/net/LinkAddress.aidl
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable LinkAddress;
|
||||
|
||||
549
framework/src/android/net/LinkAddress.java
Normal file
549
framework/src/android/net/LinkAddress.java
Normal file
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import static android.system.OsConstants.IFA_F_DADFAILED;
|
||||
import static android.system.OsConstants.IFA_F_DEPRECATED;
|
||||
import static android.system.OsConstants.IFA_F_OPTIMISTIC;
|
||||
import static android.system.OsConstants.IFA_F_PERMANENT;
|
||||
import static android.system.OsConstants.IFA_F_TENTATIVE;
|
||||
import static android.system.OsConstants.RT_SCOPE_HOST;
|
||||
import static android.system.OsConstants.RT_SCOPE_LINK;
|
||||
import static android.system.OsConstants.RT_SCOPE_SITE;
|
||||
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InterfaceAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Identifies an IP address on a network link.
|
||||
*
|
||||
* A {@code LinkAddress} consists of:
|
||||
* <ul>
|
||||
* <li>An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}).
|
||||
* The address must be unicast, as multicast addresses cannot be assigned to interfaces.
|
||||
* <li>Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties
|
||||
* of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}).
|
||||
* <li>Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which
|
||||
* the address is unique (e.g.,
|
||||
* {@code android.system.OsConstants.RT_SCOPE_LINK} or
|
||||
* {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}).
|
||||
* </ul>
|
||||
*/
|
||||
public class LinkAddress implements Parcelable {
|
||||
|
||||
/**
|
||||
* Indicates the deprecation or expiration time is unknown
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final long LIFETIME_UNKNOWN = -1;
|
||||
|
||||
/**
|
||||
* Indicates this address is permanent.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final long LIFETIME_PERMANENT = Long.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* IPv4 or IPv6 address.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||
private InetAddress address;
|
||||
|
||||
/**
|
||||
* Prefix length.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||
private int prefixLength;
|
||||
|
||||
/**
|
||||
* Address flags. A bitmask of {@code IFA_F_*} values. Note that {@link #getFlags()} may not
|
||||
* return these exact values. For example, it may set or clear the {@code IFA_F_DEPRECATED}
|
||||
* flag depending on the current preferred lifetime.
|
||||
*/
|
||||
private int flags;
|
||||
|
||||
/**
|
||||
* Address scope. One of the RT_SCOPE_* constants.
|
||||
*/
|
||||
private int scope;
|
||||
|
||||
/**
|
||||
* The time, as reported by {@link SystemClock#elapsedRealtime}, when this LinkAddress will be
|
||||
* or was deprecated. At the time existing connections can still use this address until it
|
||||
* expires, but new connections should use the new address. {@link #LIFETIME_UNKNOWN} indicates
|
||||
* this information is not available. {@link #LIFETIME_PERMANENT} indicates this
|
||||
* {@link LinkAddress} will never be deprecated.
|
||||
*/
|
||||
private long deprecationTime;
|
||||
|
||||
/**
|
||||
* The time, as reported by {@link SystemClock#elapsedRealtime}, when this {@link LinkAddress}
|
||||
* will expire and be removed from the interface. {@link #LIFETIME_UNKNOWN} indicates this
|
||||
* information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
|
||||
* will never expire.
|
||||
*/
|
||||
private long expirationTime;
|
||||
|
||||
/**
|
||||
* Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and
|
||||
* RFC 6724 section 3.2.
|
||||
* @hide
|
||||
*/
|
||||
private static int scopeForUnicastAddress(InetAddress addr) {
|
||||
if (addr.isAnyLocalAddress()) {
|
||||
return RT_SCOPE_HOST;
|
||||
}
|
||||
|
||||
if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
|
||||
return RT_SCOPE_LINK;
|
||||
}
|
||||
|
||||
// isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2
|
||||
// says that they are assigned global scope.
|
||||
if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) {
|
||||
return RT_SCOPE_SITE;
|
||||
}
|
||||
|
||||
return RT_SCOPE_UNIVERSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to check if |address| is a Unique Local IPv6 Unicast Address
|
||||
* (a.k.a. "ULA"; RFC 4193).
|
||||
*
|
||||
* Per RFC 4193 section 8, fc00::/7 identifies these addresses.
|
||||
*/
|
||||
private boolean isIpv6ULA() {
|
||||
if (isIpv6()) {
|
||||
byte[] bytes = address.getAddress();
|
||||
return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the address is IPv6.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public boolean isIpv6() {
|
||||
return address instanceof Inet6Address;
|
||||
}
|
||||
|
||||
/**
|
||||
* For backward compatibility.
|
||||
* This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
|
||||
* just yet.
|
||||
* @return true if the address is IPv6.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
|
||||
public boolean isIPv6() {
|
||||
return isIpv6();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the address is IPv4 or is a mapped IPv4 address.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public boolean isIpv4() {
|
||||
return address instanceof Inet4Address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for the constructors.
|
||||
*/
|
||||
private void init(InetAddress address, int prefixLength, int flags, int scope,
|
||||
long deprecationTime, long expirationTime) {
|
||||
if (address == null ||
|
||||
address.isMulticastAddress() ||
|
||||
prefixLength < 0 ||
|
||||
(address instanceof Inet4Address && prefixLength > 32) ||
|
||||
(prefixLength > 128)) {
|
||||
throw new IllegalArgumentException("Bad LinkAddress params " + address +
|
||||
"/" + prefixLength);
|
||||
}
|
||||
|
||||
// deprecation time and expiration time must be both provided, or neither.
|
||||
if ((deprecationTime == LIFETIME_UNKNOWN) != (expirationTime == LIFETIME_UNKNOWN)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Must not specify only one of deprecation time and expiration time");
|
||||
}
|
||||
|
||||
// deprecation time needs to be a positive value.
|
||||
if (deprecationTime != LIFETIME_UNKNOWN && deprecationTime < 0) {
|
||||
throw new IllegalArgumentException("invalid deprecation time " + deprecationTime);
|
||||
}
|
||||
|
||||
// expiration time needs to be a positive value.
|
||||
if (expirationTime != LIFETIME_UNKNOWN && expirationTime < 0) {
|
||||
throw new IllegalArgumentException("invalid expiration time " + expirationTime);
|
||||
}
|
||||
|
||||
// expiration time can't be earlier than deprecation time
|
||||
if (deprecationTime != LIFETIME_UNKNOWN && expirationTime != LIFETIME_UNKNOWN
|
||||
&& expirationTime < deprecationTime) {
|
||||
throw new IllegalArgumentException("expiration earlier than deprecation ("
|
||||
+ deprecationTime + ", " + expirationTime + ")");
|
||||
}
|
||||
|
||||
this.address = address;
|
||||
this.prefixLength = prefixLength;
|
||||
this.flags = flags;
|
||||
this.scope = scope;
|
||||
this.deprecationTime = deprecationTime;
|
||||
this.expirationTime = expirationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
|
||||
* the specified flags and scope. Flags and scope are not checked for validity.
|
||||
*
|
||||
* @param address The IP address.
|
||||
* @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
|
||||
* @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
|
||||
* @param scope An integer defining the scope in which the address is unique (e.g.,
|
||||
* {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
|
||||
int flags, int scope) {
|
||||
init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code LinkAddress} from an {@code InetAddress}, prefix length, with
|
||||
* the specified flags, scope, deprecation time, and expiration time. Flags and scope are not
|
||||
* checked for validity. The value of the {@code IFA_F_DEPRECATED} and {@code IFA_F_PERMANENT}
|
||||
* flag will be adjusted based on the passed-in lifetimes.
|
||||
*
|
||||
* @param address The IP address.
|
||||
* @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
|
||||
* @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
|
||||
* @param scope An integer defining the scope in which the address is unique (e.g.,
|
||||
* {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
|
||||
* @param deprecationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when
|
||||
* this {@link LinkAddress} will be or was deprecated. At the time
|
||||
* existing connections can still use this address until it expires, but
|
||||
* new connections should use the new address. {@link #LIFETIME_UNKNOWN}
|
||||
* indicates this information is not available.
|
||||
* {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
|
||||
* never be deprecated.
|
||||
* @param expirationTime The time, as reported by {@link SystemClock#elapsedRealtime}, when this
|
||||
* {@link LinkAddress} will expire and be removed from the interface.
|
||||
* {@link #LIFETIME_UNKNOWN} indicates this information is not available.
|
||||
* {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress} will
|
||||
* never expire.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
|
||||
int flags, int scope, long deprecationTime, long expirationTime) {
|
||||
init(address, prefixLength, flags, scope, deprecationTime, expirationTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length.
|
||||
* The flags are set to zero and the scope is determined from the address.
|
||||
* @param address The IP address.
|
||||
* @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public LinkAddress(@NonNull InetAddress address,
|
||||
@IntRange(from = 0, to = 128) int prefixLength) {
|
||||
this(address, prefixLength, 0, 0);
|
||||
this.scope = scopeForUnicastAddress(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}.
|
||||
* The flags are set to zero and the scope is determined from the address.
|
||||
* @param interfaceAddress The interface address.
|
||||
* @hide
|
||||
*/
|
||||
public LinkAddress(@NonNull InterfaceAddress interfaceAddress) {
|
||||
this(interfaceAddress.getAddress(),
|
||||
interfaceAddress.getNetworkPrefixLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
|
||||
* "2001:db8::1/64". The flags are set to zero and the scope is determined from the address.
|
||||
* @param address The string to parse.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public LinkAddress(@NonNull String address) {
|
||||
this(address, 0, 0);
|
||||
this.scope = scopeForUnicastAddress(this.address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or
|
||||
* "2001:db8::1/64", with the specified flags and scope.
|
||||
* @param address The string to parse.
|
||||
* @param flags The address flags.
|
||||
* @param scope The address scope.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public LinkAddress(@NonNull String address, int flags, int scope) {
|
||||
// This may throw an IllegalArgumentException; catching it is the caller's responsibility.
|
||||
// TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
|
||||
Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
|
||||
init(ipAndMask.first, ipAndMask.second, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64".
|
||||
* The string representation does not contain the flags and scope, just the address and prefix
|
||||
* length.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return address.getHostAddress() + "/" + prefixLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if
|
||||
* their address, prefix length, flags and scope are equal. Thus, for example, two addresses
|
||||
* that have the same address and prefix length are not equal if one of them is deprecated and
|
||||
* the other is not.
|
||||
*
|
||||
* @param obj the object to be tested for equality.
|
||||
* @return {@code true} if both objects are equal, {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof LinkAddress)) {
|
||||
return false;
|
||||
}
|
||||
LinkAddress linkAddress = (LinkAddress) obj;
|
||||
return this.address.equals(linkAddress.address)
|
||||
&& this.prefixLength == linkAddress.prefixLength
|
||||
&& this.flags == linkAddress.flags
|
||||
&& this.scope == linkAddress.scope
|
||||
&& this.deprecationTime == linkAddress.deprecationTime
|
||||
&& this.expirationTime == linkAddress.expirationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode for this address.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(address, prefixLength, flags, scope, deprecationTime, expirationTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this {@code LinkAddress} and the provided {@code LinkAddress}
|
||||
* represent the same address. Two {@code LinkAddresses} represent the same address
|
||||
* if they have the same IP address and prefix length, even if their properties are
|
||||
* different.
|
||||
*
|
||||
* @param other the {@code LinkAddress} to compare to.
|
||||
* @return {@code true} if both objects have the same address and prefix length, {@code false}
|
||||
* otherwise.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public boolean isSameAddressAs(@Nullable LinkAddress other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
return address.equals(other.address) && prefixLength == other.prefixLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link InetAddress} of this {@code LinkAddress}.
|
||||
*/
|
||||
public InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prefix length of this {@code LinkAddress}.
|
||||
*/
|
||||
@IntRange(from = 0, to = 128)
|
||||
public int getPrefixLength() {
|
||||
return prefixLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the prefix length of this {@code LinkAddress}.
|
||||
* TODO: Delete all callers and remove in favour of getPrefixLength().
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
@IntRange(from = 0, to = 128)
|
||||
public int getNetworkPrefixLength() {
|
||||
return getPrefixLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flags of this {@code LinkAddress}.
|
||||
*/
|
||||
public int getFlags() {
|
||||
int flags = this.flags;
|
||||
if (deprecationTime != LIFETIME_UNKNOWN) {
|
||||
if (SystemClock.elapsedRealtime() >= deprecationTime) {
|
||||
flags |= IFA_F_DEPRECATED;
|
||||
} else {
|
||||
// If deprecation time is in the future, or permanent.
|
||||
flags &= ~IFA_F_DEPRECATED;
|
||||
}
|
||||
}
|
||||
|
||||
if (expirationTime == LIFETIME_PERMANENT) {
|
||||
flags |= IFA_F_PERMANENT;
|
||||
} else if (expirationTime != LIFETIME_UNKNOWN) {
|
||||
// If we know this address expired or will expire in the future, then this address
|
||||
// should not be permanent.
|
||||
flags &= ~IFA_F_PERMANENT;
|
||||
}
|
||||
|
||||
// Do no touch the original flags. Return the adjusted flags here.
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scope of this {@code LinkAddress}.
|
||||
*/
|
||||
public int getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the deprecation time, as reported by {@link SystemClock#elapsedRealtime}, when this
|
||||
* {@link LinkAddress} will be or was deprecated. At the time existing connections can still use
|
||||
* this address until it expires, but new connections should use the new address.
|
||||
*
|
||||
* @return The deprecation time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
|
||||
* information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
|
||||
* will never be deprecated.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public long getDeprecationTime() {
|
||||
return deprecationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expiration time, as reported by {@link SystemClock#elapsedRealtime}, when this
|
||||
* {@link LinkAddress} will expire and be removed from the interface.
|
||||
*
|
||||
* @return The expiration time in milliseconds. {@link #LIFETIME_UNKNOWN} indicates this
|
||||
* information is not available. {@link #LIFETIME_PERMANENT} indicates this {@link LinkAddress}
|
||||
* will never expire.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public long getExpirationTime() {
|
||||
return expirationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this {@code LinkAddress} is global scope and preferred (i.e., not currently
|
||||
* deprecated).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public boolean isGlobalPreferred() {
|
||||
/**
|
||||
* Note that addresses flagged as IFA_F_OPTIMISTIC are
|
||||
* simultaneously flagged as IFA_F_TENTATIVE (when the tentative
|
||||
* state has cleared either DAD has succeeded or failed, and both
|
||||
* flags are cleared regardless).
|
||||
*/
|
||||
int flags = getFlags();
|
||||
return (scope == RT_SCOPE_UNIVERSE
|
||||
&& !isIpv6ULA()
|
||||
&& (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
|
||||
&& ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface.
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface.
|
||||
*/
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeByteArray(address.getAddress());
|
||||
dest.writeInt(prefixLength);
|
||||
dest.writeInt(this.flags);
|
||||
dest.writeInt(scope);
|
||||
dest.writeLong(deprecationTime);
|
||||
dest.writeLong(expirationTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface.
|
||||
*/
|
||||
public static final @android.annotation.NonNull Creator<LinkAddress> CREATOR =
|
||||
new Creator<LinkAddress>() {
|
||||
public LinkAddress createFromParcel(Parcel in) {
|
||||
InetAddress address = null;
|
||||
try {
|
||||
address = InetAddress.getByAddress(in.createByteArray());
|
||||
} catch (UnknownHostException e) {
|
||||
// Nothing we can do here. When we call the constructor, we'll throw an
|
||||
// IllegalArgumentException, because a LinkAddress can't have a null
|
||||
// InetAddress.
|
||||
}
|
||||
int prefixLength = in.readInt();
|
||||
int flags = in.readInt();
|
||||
int scope = in.readInt();
|
||||
long deprecationTime = in.readLong();
|
||||
long expirationTime = in.readLong();
|
||||
return new LinkAddress(address, prefixLength, flags, scope, deprecationTime,
|
||||
expirationTime);
|
||||
}
|
||||
|
||||
public LinkAddress[] newArray(int size) {
|
||||
return new LinkAddress[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
20
framework/src/android/net/LinkProperties.aidl
Normal file
20
framework/src/android/net/LinkProperties.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2010 The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable LinkProperties;
|
||||
1823
framework/src/android/net/LinkProperties.java
Normal file
1823
framework/src/android/net/LinkProperties.java
Normal file
File diff suppressed because it is too large
Load Diff
20
framework/src/android/net/MacAddress.aidl
Normal file
20
framework/src/android/net/MacAddress.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable MacAddress;
|
||||
400
framework/src/android/net/MacAddress.java
Normal file
400
framework/src/android/net/MacAddress.java
Normal file
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.net.module.util.MacAddressUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Representation of a MAC address.
|
||||
*
|
||||
* This class only supports 48 bits long addresses and does not support 64 bits long addresses.
|
||||
* Instances of this class are immutable. This class provides implementations of hashCode()
|
||||
* and equals() that make it suitable for use as keys in standard implementations of
|
||||
* {@link java.util.Map}.
|
||||
*/
|
||||
public final class MacAddress implements Parcelable {
|
||||
|
||||
private static final int ETHER_ADDR_LEN = 6;
|
||||
private static final byte[] ETHER_ADDR_BROADCAST = addr(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
|
||||
|
||||
/**
|
||||
* The MacAddress representing the unique broadcast MAC address.
|
||||
*/
|
||||
public static final MacAddress BROADCAST_ADDRESS = MacAddress.fromBytes(ETHER_ADDR_BROADCAST);
|
||||
|
||||
/**
|
||||
* The MacAddress zero MAC address.
|
||||
*
|
||||
* <p>Not publicly exposed or treated specially since the OUI 00:00:00 is registered.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0);
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = { "TYPE_" }, value = {
|
||||
TYPE_UNKNOWN,
|
||||
TYPE_UNICAST,
|
||||
TYPE_MULTICAST,
|
||||
TYPE_BROADCAST,
|
||||
})
|
||||
public @interface MacAddressType { }
|
||||
|
||||
/** @hide Indicates a MAC address of unknown type. */
|
||||
public static final int TYPE_UNKNOWN = 0;
|
||||
/** Indicates a MAC address is a unicast address. */
|
||||
public static final int TYPE_UNICAST = 1;
|
||||
/** Indicates a MAC address is a multicast address. */
|
||||
public static final int TYPE_MULTICAST = 2;
|
||||
/** Indicates a MAC address is the broadcast address. */
|
||||
public static final int TYPE_BROADCAST = 3;
|
||||
|
||||
private static final long VALID_LONG_MASK = (1L << 48) - 1;
|
||||
private static final long LOCALLY_ASSIGNED_MASK = MacAddress.fromString("2:0:0:0:0:0").mAddr;
|
||||
private static final long MULTICAST_MASK = MacAddress.fromString("1:0:0:0:0:0").mAddr;
|
||||
private static final long OUI_MASK = MacAddress.fromString("ff:ff:ff:0:0:0").mAddr;
|
||||
private static final long NIC_MASK = MacAddress.fromString("0:0:0:ff:ff:ff").mAddr;
|
||||
private static final MacAddress BASE_GOOGLE_MAC = MacAddress.fromString("da:a1:19:0:0:0");
|
||||
/** Default wifi MAC address used for a special purpose **/
|
||||
private static final MacAddress DEFAULT_MAC_ADDRESS =
|
||||
MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
|
||||
|
||||
// Internal representation of the MAC address as a single 8 byte long.
|
||||
// The encoding scheme sets the two most significant bytes to 0. The 6 bytes of the
|
||||
// MAC address are encoded in the 6 least significant bytes of the long, where the first
|
||||
// byte of the array is mapped to the 3rd highest logical byte of the long, the second
|
||||
// byte of the array is mapped to the 4th highest logical byte of the long, and so on.
|
||||
private final long mAddr;
|
||||
|
||||
private MacAddress(long addr) {
|
||||
mAddr = (VALID_LONG_MASK & addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this address.
|
||||
*
|
||||
* @return the int constant representing the MAC address type of this MacAddress.
|
||||
*/
|
||||
public @MacAddressType int getAddressType() {
|
||||
if (equals(BROADCAST_ADDRESS)) {
|
||||
return TYPE_BROADCAST;
|
||||
}
|
||||
if ((mAddr & MULTICAST_MASK) != 0) {
|
||||
return TYPE_MULTICAST;
|
||||
}
|
||||
return TYPE_UNICAST;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if this MacAddress is a locally assigned address.
|
||||
*/
|
||||
public boolean isLocallyAssigned() {
|
||||
return (mAddr & LOCALLY_ASSIGNED_MASK) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this MacAddress to a byte array.
|
||||
*
|
||||
* The returned array is in network order. For example, if this MacAddress is 1:2:3:4:5:6,
|
||||
* the returned array is [1, 2, 3, 4, 5, 6].
|
||||
*
|
||||
* @return a byte array representation of this MacAddress.
|
||||
*/
|
||||
public @NonNull byte[] toByteArray() {
|
||||
return byteAddrFromLongAddr(mAddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable representation of this MacAddress.
|
||||
* The exact format is implementation-dependent and should not be assumed to have any
|
||||
* particular format.
|
||||
*/
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return stringAddrFromLongAddr(mAddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a String representation of the OUI part of this MacAddress made of 3 hexadecimal
|
||||
* numbers in [0,ff] joined by ':' characters.
|
||||
*/
|
||||
public @NonNull String toOuiString() {
|
||||
return String.format(
|
||||
"%02x:%02x:%02x", (mAddr >> 40) & 0xff, (mAddr >> 32) & 0xff, (mAddr >> 24) & 0xff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) ((mAddr >> 32) ^ mAddr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof MacAddress) && ((MacAddress) o).mAddr == mAddr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeLong(mAddr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Parcelable.Creator<MacAddress> CREATOR =
|
||||
new Parcelable.Creator<MacAddress>() {
|
||||
public MacAddress createFromParcel(Parcel in) {
|
||||
return new MacAddress(in.readLong());
|
||||
}
|
||||
|
||||
public MacAddress[] newArray(int size) {
|
||||
return new MacAddress[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the given byte array is an valid MAC address.
|
||||
* A valid byte array representation for a MacAddress is a non-null array of length 6.
|
||||
*
|
||||
* @param addr a byte array.
|
||||
* @return true if the given byte array is not null and has the length of a MAC address.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static boolean isMacAddress(byte[] addr) {
|
||||
return MacAddressUtils.isMacAddress(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MAC address type of the MAC address represented by the given byte array,
|
||||
* or null if the given byte array does not represent a MAC address.
|
||||
* A valid byte array representation for a MacAddress is a non-null array of length 6.
|
||||
*
|
||||
* @param addr a byte array representing a MAC address.
|
||||
* @return the int constant representing the MAC address type of the MAC address represented
|
||||
* by the given byte array, or type UNKNOWN if the byte array is not a valid MAC address.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static int macAddressType(byte[] addr) {
|
||||
if (!isMacAddress(addr)) {
|
||||
return TYPE_UNKNOWN;
|
||||
}
|
||||
return MacAddress.fromBytes(addr).getAddressType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String representation of a MAC address to a byte array representation.
|
||||
* A valid String representation for a MacAddress is a series of 6 values in the
|
||||
* range [0,ff] printed in hexadecimal and joined by ':' characters.
|
||||
*
|
||||
* @param addr a String representation of a MAC address.
|
||||
* @return the byte representation of the MAC address.
|
||||
* @throws IllegalArgumentException if the given String is not a valid representation.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static @NonNull byte[] byteAddrFromStringAddr(String addr) {
|
||||
Preconditions.checkNotNull(addr);
|
||||
String[] parts = addr.split(":");
|
||||
if (parts.length != ETHER_ADDR_LEN) {
|
||||
throw new IllegalArgumentException(addr + " was not a valid MAC address");
|
||||
}
|
||||
byte[] bytes = new byte[ETHER_ADDR_LEN];
|
||||
for (int i = 0; i < ETHER_ADDR_LEN; i++) {
|
||||
int x = Integer.valueOf(parts[i], 16);
|
||||
if (x < 0 || 0xff < x) {
|
||||
throw new IllegalArgumentException(addr + "was not a valid MAC address");
|
||||
}
|
||||
bytes[i] = (byte) x;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array representation of a MAC address to a String representation made
|
||||
* of 6 hexadecimal numbers in [0,ff] joined by ':' characters.
|
||||
* A valid byte array representation for a MacAddress is a non-null array of length 6.
|
||||
*
|
||||
* @param addr a byte array representation of a MAC address.
|
||||
* @return the String representation of the MAC address.
|
||||
* @throws IllegalArgumentException if the given byte array is not a valid representation.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static @NonNull String stringAddrFromByteAddr(byte[] addr) {
|
||||
if (!isMacAddress(addr)) {
|
||||
return null;
|
||||
}
|
||||
return String.format("%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
|
||||
}
|
||||
|
||||
private static byte[] byteAddrFromLongAddr(long addr) {
|
||||
return MacAddressUtils.byteAddrFromLongAddr(addr);
|
||||
}
|
||||
|
||||
private static long longAddrFromByteAddr(byte[] addr) {
|
||||
return MacAddressUtils.longAddrFromByteAddr(addr);
|
||||
}
|
||||
|
||||
// Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr))
|
||||
// that avoids the allocation of an intermediary byte[].
|
||||
private static long longAddrFromStringAddr(String addr) {
|
||||
Preconditions.checkNotNull(addr);
|
||||
String[] parts = addr.split(":");
|
||||
if (parts.length != ETHER_ADDR_LEN) {
|
||||
throw new IllegalArgumentException(addr + " was not a valid MAC address");
|
||||
}
|
||||
long longAddr = 0;
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
int x = Integer.valueOf(parts[i], 16);
|
||||
if (x < 0 || 0xff < x) {
|
||||
throw new IllegalArgumentException(addr + "was not a valid MAC address");
|
||||
}
|
||||
longAddr = x + (longAddr << 8);
|
||||
}
|
||||
return longAddr;
|
||||
}
|
||||
|
||||
// Internal conversion function equivalent to stringAddrFromByteAddr(byteAddrFromLongAddr(addr))
|
||||
// that avoids the allocation of an intermediary byte[].
|
||||
private static @NonNull String stringAddrFromLongAddr(long addr) {
|
||||
return String.format("%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
(addr >> 40) & 0xff,
|
||||
(addr >> 32) & 0xff,
|
||||
(addr >> 24) & 0xff,
|
||||
(addr >> 16) & 0xff,
|
||||
(addr >> 8) & 0xff,
|
||||
addr & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MacAddress from the given String representation. A valid String representation
|
||||
* for a MacAddress is a series of 6 values in the range [0,ff] printed in hexadecimal
|
||||
* and joined by ':' characters.
|
||||
*
|
||||
* @param addr a String representation of a MAC address.
|
||||
* @return the MacAddress corresponding to the given String representation.
|
||||
* @throws IllegalArgumentException if the given String is not a valid representation.
|
||||
*/
|
||||
public static @NonNull MacAddress fromString(@NonNull String addr) {
|
||||
return new MacAddress(longAddrFromStringAddr(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MacAddress from the given byte array representation.
|
||||
* A valid byte array representation for a MacAddress is a non-null array of length 6.
|
||||
*
|
||||
* @param addr a byte array representation of a MAC address.
|
||||
* @return the MacAddress corresponding to the given byte array representation.
|
||||
* @throws IllegalArgumentException if the given byte array is not a valid representation.
|
||||
*/
|
||||
public static @NonNull MacAddress fromBytes(@NonNull byte[] addr) {
|
||||
return new MacAddress(longAddrFromByteAddr(addr));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a generated MAC address whose 24 least significant bits constituting the
|
||||
* NIC part of the address are randomly selected and has Google OUI base.
|
||||
*
|
||||
* The locally assigned bit is always set to 1. The multicast bit is always set to 0.
|
||||
*
|
||||
* @return a random locally assigned, unicast MacAddress with Google OUI.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static @NonNull MacAddress createRandomUnicastAddressWithGoogleBase() {
|
||||
return MacAddressUtils.createRandomUnicastAddress(BASE_GOOGLE_MAC, new SecureRandom());
|
||||
}
|
||||
|
||||
// Convenience function for working around the lack of byte literals.
|
||||
private static byte[] addr(int... in) {
|
||||
if (in.length != ETHER_ADDR_LEN) {
|
||||
throw new IllegalArgumentException(Arrays.toString(in)
|
||||
+ " was not an array with length equal to " + ETHER_ADDR_LEN);
|
||||
}
|
||||
byte[] out = new byte[ETHER_ADDR_LEN];
|
||||
for (int i = 0; i < ETHER_ADDR_LEN; i++) {
|
||||
out[i] = (byte) in[i];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this MAC Address matches the provided range.
|
||||
*
|
||||
* @param baseAddress MacAddress representing the base address to compare with.
|
||||
* @param mask MacAddress representing the mask to use during comparison.
|
||||
* @return true if this MAC Address matches the given range.
|
||||
*
|
||||
*/
|
||||
public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
|
||||
Preconditions.checkNotNull(baseAddress);
|
||||
Preconditions.checkNotNull(mask);
|
||||
return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a link-local Inet6Address from the MAC address. The EUI-48 MAC address is converted
|
||||
* to an EUI-64 MAC address per RFC 4291. The resulting EUI-64 is used to construct a link-local
|
||||
* IPv6 address per RFC 4862.
|
||||
*
|
||||
* @return A link-local Inet6Address constructed from the MAC address.
|
||||
*/
|
||||
public @Nullable Inet6Address getLinkLocalIpv6FromEui48Mac() {
|
||||
byte[] macEui48Bytes = toByteArray();
|
||||
byte[] addr = new byte[16];
|
||||
|
||||
addr[0] = (byte) 0xfe;
|
||||
addr[1] = (byte) 0x80;
|
||||
addr[8] = (byte) (macEui48Bytes[0] ^ (byte) 0x02); // flip the link-local bit
|
||||
addr[9] = macEui48Bytes[1];
|
||||
addr[10] = macEui48Bytes[2];
|
||||
addr[11] = (byte) 0xff;
|
||||
addr[12] = (byte) 0xfe;
|
||||
addr[13] = macEui48Bytes[3];
|
||||
addr[14] = macEui48Bytes[4];
|
||||
addr[15] = macEui48Bytes[5];
|
||||
|
||||
try {
|
||||
return Inet6Address.getByAddress(null, addr, 0);
|
||||
} catch (UnknownHostException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
144
framework/src/android/net/NattKeepalivePacketData.java
Normal file
144
framework/src/android/net/NattKeepalivePacketData.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS;
|
||||
import static android.net.InvalidPacketException.ERROR_INVALID_PORT;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.system.OsConstants;
|
||||
|
||||
import com.android.net.module.util.IpUtils;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Objects;
|
||||
|
||||
/** @hide */
|
||||
@SystemApi
|
||||
public final class NattKeepalivePacketData extends KeepalivePacketData implements Parcelable {
|
||||
private static final int IPV4_HEADER_LENGTH = 20;
|
||||
private static final int UDP_HEADER_LENGTH = 8;
|
||||
|
||||
// This should only be constructed via static factory methods, such as
|
||||
// nattKeepalivePacket
|
||||
public NattKeepalivePacketData(@NonNull InetAddress srcAddress, int srcPort,
|
||||
@NonNull InetAddress dstAddress, int dstPort, @NonNull byte[] data) throws
|
||||
InvalidPacketException {
|
||||
super(srcAddress, srcPort, dstAddress, dstPort, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create Nat-T keepalive packet structure.
|
||||
* @hide
|
||||
*/
|
||||
public static NattKeepalivePacketData nattKeepalivePacket(
|
||||
InetAddress srcAddress, int srcPort, InetAddress dstAddress, int dstPort)
|
||||
throws InvalidPacketException {
|
||||
|
||||
if (!(srcAddress instanceof Inet4Address) || !(dstAddress instanceof Inet4Address)) {
|
||||
throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
|
||||
}
|
||||
|
||||
if (dstPort != NattSocketKeepalive.NATT_PORT) {
|
||||
throw new InvalidPacketException(ERROR_INVALID_PORT);
|
||||
}
|
||||
|
||||
int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
|
||||
ByteBuffer buf = ByteBuffer.allocate(length);
|
||||
buf.order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putShort((short) 0x4500); // IP version and TOS
|
||||
buf.putShort((short) length);
|
||||
buf.putInt(0); // ID, flags, offset
|
||||
buf.put((byte) 64); // TTL
|
||||
buf.put((byte) OsConstants.IPPROTO_UDP);
|
||||
int ipChecksumOffset = buf.position();
|
||||
buf.putShort((short) 0); // IP checksum
|
||||
buf.put(srcAddress.getAddress());
|
||||
buf.put(dstAddress.getAddress());
|
||||
buf.putShort((short) srcPort);
|
||||
buf.putShort((short) dstPort);
|
||||
buf.putShort((short) (length - 20)); // UDP length
|
||||
int udpChecksumOffset = buf.position();
|
||||
buf.putShort((short) 0); // UDP checksum
|
||||
buf.put((byte) 0xff); // NAT-T keepalive
|
||||
buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
|
||||
buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
|
||||
|
||||
return new NattKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
|
||||
}
|
||||
|
||||
/** Parcelable Implementation */
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Write to parcel */
|
||||
public void writeToParcel(@NonNull Parcel out, int flags) {
|
||||
out.writeString(getSrcAddress().getHostAddress());
|
||||
out.writeString(getDstAddress().getHostAddress());
|
||||
out.writeInt(getSrcPort());
|
||||
out.writeInt(getDstPort());
|
||||
}
|
||||
|
||||
/** Parcelable Creator */
|
||||
public static final @NonNull Parcelable.Creator<NattKeepalivePacketData> CREATOR =
|
||||
new Parcelable.Creator<NattKeepalivePacketData>() {
|
||||
public NattKeepalivePacketData createFromParcel(Parcel in) {
|
||||
final InetAddress srcAddress =
|
||||
InetAddresses.parseNumericAddress(in.readString());
|
||||
final InetAddress dstAddress =
|
||||
InetAddresses.parseNumericAddress(in.readString());
|
||||
final int srcPort = in.readInt();
|
||||
final int dstPort = in.readInt();
|
||||
try {
|
||||
return NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort,
|
||||
dstAddress, dstPort);
|
||||
} catch (InvalidPacketException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid NAT-T keepalive data: " + e.getError());
|
||||
}
|
||||
}
|
||||
|
||||
public NattKeepalivePacketData[] newArray(int size) {
|
||||
return new NattKeepalivePacketData[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable final Object o) {
|
||||
if (!(o instanceof NattKeepalivePacketData)) return false;
|
||||
final NattKeepalivePacketData other = (NattKeepalivePacketData) o;
|
||||
final InetAddress srcAddress = getSrcAddress();
|
||||
final InetAddress dstAddress = getDstAddress();
|
||||
return srcAddress.equals(other.getSrcAddress())
|
||||
&& dstAddress.equals(other.getDstAddress())
|
||||
&& getSrcPort() == other.getSrcPort()
|
||||
&& getDstPort() == other.getDstPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort());
|
||||
}
|
||||
}
|
||||
77
framework/src/android/net/NattSocketKeepalive.java
Normal file
77
framework/src/android/net/NattSocketKeepalive.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/** @hide */
|
||||
public final class NattSocketKeepalive extends SocketKeepalive {
|
||||
/** The NAT-T destination port for IPsec */
|
||||
public static final int NATT_PORT = 4500;
|
||||
|
||||
@NonNull private final InetAddress mSource;
|
||||
@NonNull private final InetAddress mDestination;
|
||||
private final int mResourceId;
|
||||
|
||||
NattSocketKeepalive(@NonNull IConnectivityManager service,
|
||||
@NonNull Network network,
|
||||
@NonNull ParcelFileDescriptor pfd,
|
||||
int resourceId,
|
||||
@NonNull InetAddress source,
|
||||
@NonNull InetAddress destination,
|
||||
@NonNull Executor executor,
|
||||
@NonNull Callback callback) {
|
||||
super(service, network, pfd, executor, callback);
|
||||
mSource = source;
|
||||
mDestination = destination;
|
||||
mResourceId = resourceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
void startImpl(int intervalSec) {
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId,
|
||||
intervalSec, mCallback,
|
||||
mSource.getHostAddress(), mDestination.getHostAddress());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error starting socket keepalive: ", e);
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopImpl() {
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
if (mSlot != null) {
|
||||
mService.stopKeepalive(mNetwork, mSlot);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error stopping socket keepalive: ", e);
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
20
framework/src/android/net/Network.aidl
Normal file
20
framework/src/android/net/Network.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2014 The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable Network;
|
||||
535
framework/src/android/net/Network.java
Normal file
535
framework/src/android/net/Network.java
Normal file
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.system.OsConstants;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.okhttp.internalandroidapi.Dns;
|
||||
import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
|
||||
/**
|
||||
* Identifies a {@code Network}. This is supplied to applications via
|
||||
* {@link ConnectivityManager.NetworkCallback} in response to the active
|
||||
* {@link ConnectivityManager#requestNetwork} or passive
|
||||
* {@link ConnectivityManager#registerNetworkCallback} calls.
|
||||
* It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis
|
||||
* through a targeted {@link SocketFactory} or process-wide via
|
||||
* {@link ConnectivityManager#bindProcessToNetwork}.
|
||||
*/
|
||||
public class Network implements Parcelable {
|
||||
|
||||
/**
|
||||
* The unique id of the network.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public final int netId;
|
||||
|
||||
// Objects used to perform per-network operations such as getSocketFactory
|
||||
// and openConnection, and a lock to protect access to them.
|
||||
private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null;
|
||||
// mUrlConnectionFactory is initialized lazily when it is first needed.
|
||||
@GuardedBy("mLock")
|
||||
private HttpURLConnectionFactory mUrlConnectionFactory;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
// Default connection pool values. These are evaluated at startup, just
|
||||
// like the OkHttp code. Also like the OkHttp code, we will throw parse
|
||||
// exceptions at class loading time if the properties are set but are not
|
||||
// valid integers.
|
||||
private static final boolean httpKeepAlive =
|
||||
Boolean.parseBoolean(System.getProperty("http.keepAlive", "true"));
|
||||
private static final int httpMaxConnections =
|
||||
httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0;
|
||||
private static final long httpKeepAliveDurationMs =
|
||||
Long.parseLong(System.getProperty("http.keepAliveDuration", "300000")); // 5 minutes.
|
||||
// Value used to obfuscate network handle longs.
|
||||
// The HANDLE_MAGIC value MUST be kept in sync with the corresponding
|
||||
// value in the native/android/net.c NDK implementation.
|
||||
private static final long HANDLE_MAGIC = 0xcafed00dL;
|
||||
private static final int HANDLE_MAGIC_SIZE = 32;
|
||||
|
||||
// A boolean to control how getAllByName()/getByName() behaves in the face
|
||||
// of Private DNS.
|
||||
//
|
||||
// When true, these calls will request that DNS resolution bypass any
|
||||
// Private DNS that might otherwise apply. Use of this feature is restricted
|
||||
// and permission checks are made by netd (attempts to bypass Private DNS
|
||||
// without appropriate permission are silently turned into vanilla DNS
|
||||
// requests). This only affects DNS queries made using this network object.
|
||||
//
|
||||
// It it not parceled to receivers because (a) it can be set or cleared at
|
||||
// anytime and (b) receivers should be explicit about attempts to bypass
|
||||
// Private DNS so that the intent of the code is easily determined and
|
||||
// code search audits are possible.
|
||||
private final transient boolean mPrivateDnsBypass;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public Network(int netId) {
|
||||
this(netId, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public Network(int netId, boolean privateDnsBypass) {
|
||||
this.netId = netId;
|
||||
this.mPrivateDnsBypass = privateDnsBypass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public Network(@NonNull Network that) {
|
||||
this(that.netId, that.mPrivateDnsBypass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operates the same as {@code InetAddress.getAllByName} except that host
|
||||
* resolution is done on this network.
|
||||
*
|
||||
* @param host the hostname or literal IP string to be resolved.
|
||||
* @return the array of addresses associated with the specified host.
|
||||
* @throws UnknownHostException if the address lookup fails.
|
||||
*/
|
||||
public InetAddress[] getAllByName(String host) throws UnknownHostException {
|
||||
return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
|
||||
}
|
||||
|
||||
/**
|
||||
* Operates the same as {@code InetAddress.getByName} except that host
|
||||
* resolution is done on this network.
|
||||
*
|
||||
* @param host the hostname to be resolved to an address or {@code null}.
|
||||
* @return the {@code InetAddress} instance representing the host.
|
||||
* @throws UnknownHostException
|
||||
* if the address lookup fails.
|
||||
*/
|
||||
public InetAddress getByName(String host) throws UnknownHostException {
|
||||
return InetAddress.getByNameOnNet(host, getNetIdForResolv());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a Network object for which Private DNS is to be bypassed when attempting
|
||||
* to use {@link #getAllByName(String)}/{@link #getByName(String)} methods on the given
|
||||
* instance for hostname resolution.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public @NonNull Network getPrivateDnsBypassingCopy() {
|
||||
return new Network(netId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique id of the network.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public int getNetId() {
|
||||
return netId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a netid marked with the Private DNS bypass flag.
|
||||
*
|
||||
* This flag must be kept in sync with the NETID_USE_LOCAL_NAMESERVERS flag
|
||||
* in system/netd/include/NetdClient.h.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public int getNetIdForResolv() {
|
||||
return mPrivateDnsBypass
|
||||
? (int) (0x80000000L | (long) netId) // Non-portable DNS resolution flag.
|
||||
: netId;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@code SocketFactory} that produces {@code Socket}'s bound to this network.
|
||||
*/
|
||||
private class NetworkBoundSocketFactory extends SocketFactory {
|
||||
private Socket connectToHost(String host, int port, SocketAddress localAddress)
|
||||
throws IOException {
|
||||
// Lookup addresses only on this Network.
|
||||
InetAddress[] hostAddresses = getAllByName(host);
|
||||
// Try all addresses.
|
||||
for (int i = 0; i < hostAddresses.length; i++) {
|
||||
try {
|
||||
Socket socket = createSocket();
|
||||
boolean failed = true;
|
||||
try {
|
||||
if (localAddress != null) socket.bind(localAddress);
|
||||
socket.connect(new InetSocketAddress(hostAddresses[i], port));
|
||||
failed = false;
|
||||
return socket;
|
||||
} finally {
|
||||
if (failed) IoUtils.closeQuietly(socket);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
if (i == (hostAddresses.length - 1)) throw e;
|
||||
}
|
||||
}
|
||||
throw new UnknownHostException(host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
|
||||
throws IOException {
|
||||
return connectToHost(host, port, new InetSocketAddress(localHost, localPort));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
|
||||
int localPort) throws IOException {
|
||||
Socket socket = createSocket();
|
||||
boolean failed = true;
|
||||
try {
|
||||
socket.bind(new InetSocketAddress(localAddress, localPort));
|
||||
socket.connect(new InetSocketAddress(address, port));
|
||||
failed = false;
|
||||
} finally {
|
||||
if (failed) IoUtils.closeQuietly(socket);
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
Socket socket = createSocket();
|
||||
boolean failed = true;
|
||||
try {
|
||||
socket.connect(new InetSocketAddress(host, port));
|
||||
failed = false;
|
||||
} finally {
|
||||
if (failed) IoUtils.closeQuietly(socket);
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException {
|
||||
return connectToHost(host, port, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
Socket socket = new Socket();
|
||||
boolean failed = true;
|
||||
try {
|
||||
bindSocket(socket);
|
||||
failed = false;
|
||||
} finally {
|
||||
if (failed) IoUtils.closeQuietly(socket);
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link SocketFactory} bound to this network. Any {@link Socket} created by
|
||||
* this factory will have its traffic sent over this {@code Network}. Note that if this
|
||||
* {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the
|
||||
* past or future will cease to work.
|
||||
*
|
||||
* @return a {@link SocketFactory} which produces {@link Socket} instances bound to this
|
||||
* {@code Network}.
|
||||
*/
|
||||
public SocketFactory getSocketFactory() {
|
||||
if (mNetworkBoundSocketFactory == null) {
|
||||
synchronized (mLock) {
|
||||
if (mNetworkBoundSocketFactory == null) {
|
||||
mNetworkBoundSocketFactory = new NetworkBoundSocketFactory();
|
||||
}
|
||||
}
|
||||
}
|
||||
return mNetworkBoundSocketFactory;
|
||||
}
|
||||
|
||||
private static HttpURLConnectionFactory createUrlConnectionFactory(Dns dnsLookup) {
|
||||
// Set configuration on the HttpURLConnectionFactory that will be good for all
|
||||
// connections created by this Network. Configuration that might vary is left
|
||||
// until openConnection() and passed as arguments.
|
||||
HttpURLConnectionFactory urlConnectionFactory = new HttpURLConnectionFactory();
|
||||
urlConnectionFactory.setDns(dnsLookup); // Let traffic go via dnsLookup
|
||||
// A private connection pool just for this Network.
|
||||
urlConnectionFactory.setNewConnectionPool(httpMaxConnections,
|
||||
httpKeepAliveDurationMs, TimeUnit.MILLISECONDS);
|
||||
return urlConnectionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent
|
||||
* on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}.
|
||||
*
|
||||
* @return a {@code URLConnection} to the resource referred to by this URL.
|
||||
* @throws MalformedURLException if the URL protocol is not HTTP or HTTPS.
|
||||
* @throws IOException if an error occurs while opening the connection.
|
||||
* @see java.net.URL#openConnection()
|
||||
*/
|
||||
public URLConnection openConnection(URL url) throws IOException {
|
||||
final ConnectivityManager cm = ConnectivityManager.getInstanceOrNull();
|
||||
if (cm == null) {
|
||||
throw new IOException("No ConnectivityManager yet constructed, please construct one");
|
||||
}
|
||||
// TODO: Should this be optimized to avoid fetching the global proxy for every request?
|
||||
final ProxyInfo proxyInfo = cm.getProxyForNetwork(this);
|
||||
final java.net.Proxy proxy;
|
||||
if (proxyInfo != null) {
|
||||
proxy = proxyInfo.makeProxy();
|
||||
} else {
|
||||
proxy = java.net.Proxy.NO_PROXY;
|
||||
}
|
||||
return openConnection(url, proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent
|
||||
* on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}.
|
||||
*
|
||||
* @param proxy the proxy through which the connection will be established.
|
||||
* @return a {@code URLConnection} to the resource referred to by this URL.
|
||||
* @throws MalformedURLException if the URL protocol is not HTTP or HTTPS.
|
||||
* @throws IllegalArgumentException if the argument proxy is null.
|
||||
* @throws IOException if an error occurs while opening the connection.
|
||||
* @see java.net.URL#openConnection()
|
||||
*/
|
||||
public URLConnection openConnection(URL url, java.net.Proxy proxy) throws IOException {
|
||||
if (proxy == null) throw new IllegalArgumentException("proxy is null");
|
||||
// TODO: This creates a connection pool and host resolver for
|
||||
// every Network object, instead of one for every NetId. This is
|
||||
// suboptimal, because an app could potentially have more than one
|
||||
// Network object for the same NetId, causing increased memory footprint
|
||||
// and performance penalties due to lack of connection reuse (connection
|
||||
// setup time, congestion window growth time, etc.).
|
||||
//
|
||||
// Instead, investigate only having one connection pool and host resolver
|
||||
// for every NetId, perhaps by using a static HashMap of NetIds to
|
||||
// connection pools and host resolvers. The tricky part is deciding when
|
||||
// to remove a map entry; a WeakHashMap shouldn't be used because whether
|
||||
// a Network is referenced doesn't correlate with whether a new Network
|
||||
// will be instantiated in the near future with the same NetID. A good
|
||||
// solution would involve purging empty (or when all connections are timed
|
||||
// out) ConnectionPools.
|
||||
final HttpURLConnectionFactory urlConnectionFactory;
|
||||
synchronized (mLock) {
|
||||
if (mUrlConnectionFactory == null) {
|
||||
Dns dnsLookup = hostname -> Arrays.asList(getAllByName(hostname));
|
||||
mUrlConnectionFactory = createUrlConnectionFactory(dnsLookup);
|
||||
}
|
||||
urlConnectionFactory = mUrlConnectionFactory;
|
||||
}
|
||||
SocketFactory socketFactory = getSocketFactory();
|
||||
return urlConnectionFactory.openConnection(url, socketFactory, proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the specified {@link DatagramSocket} to this {@code Network}. All data traffic on the
|
||||
* socket will be sent on this {@code Network}, irrespective of any process-wide network binding
|
||||
* set by {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be
|
||||
* connected.
|
||||
*/
|
||||
public void bindSocket(DatagramSocket socket) throws IOException {
|
||||
// Query a property of the underlying socket to ensure that the socket's file descriptor
|
||||
// exists, is available to bind to a network and is not closed.
|
||||
socket.getReuseAddress();
|
||||
final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket);
|
||||
bindSocket(pfd.getFileDescriptor());
|
||||
// ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
|
||||
// dup share the underlying socket in the kernel. The socket is never truly closed until the
|
||||
// last fd pointing to the socket being closed. So close the dup one after binding the
|
||||
// socket to control the lifetime of the dup fd.
|
||||
pfd.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket
|
||||
* will be sent on this {@code Network}, irrespective of any process-wide network binding set by
|
||||
* {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected.
|
||||
*/
|
||||
public void bindSocket(Socket socket) throws IOException {
|
||||
// Query a property of the underlying socket to ensure that the socket's file descriptor
|
||||
// exists, is available to bind to a network and is not closed.
|
||||
socket.getReuseAddress();
|
||||
final ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
|
||||
bindSocket(pfd.getFileDescriptor());
|
||||
// ParcelFileDescriptor.fromSocket() creates a dup of the original fd. The original and the
|
||||
// dup share the underlying socket in the kernel. The socket is never truly closed until the
|
||||
// last fd pointing to the socket being closed. So close the dup one after binding the
|
||||
// socket to control the lifetime of the dup fd.
|
||||
pfd.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the specified {@link FileDescriptor} to this {@code Network}. All data traffic on the
|
||||
* socket represented by this file descriptor will be sent on this {@code Network},
|
||||
* irrespective of any process-wide network binding set by
|
||||
* {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected.
|
||||
*/
|
||||
public void bindSocket(FileDescriptor fd) throws IOException {
|
||||
try {
|
||||
final SocketAddress peer = Os.getpeername(fd);
|
||||
final InetAddress inetPeer = ((InetSocketAddress) peer).getAddress();
|
||||
if (!inetPeer.isAnyLocalAddress()) {
|
||||
// Apparently, the kernel doesn't update a connected UDP socket's
|
||||
// routing upon mark changes.
|
||||
throw new SocketException("Socket is connected");
|
||||
}
|
||||
} catch (ErrnoException e) {
|
||||
// getpeername() failed.
|
||||
if (e.errno != OsConstants.ENOTCONN) {
|
||||
throw e.rethrowAsSocketException();
|
||||
}
|
||||
} catch (ClassCastException e) {
|
||||
// Wasn't an InetSocketAddress.
|
||||
throw new SocketException("Only AF_INET/AF_INET6 sockets supported");
|
||||
}
|
||||
|
||||
final int err = NetworkUtils.bindSocketToNetwork(fd, netId);
|
||||
if (err != 0) {
|
||||
// bindSocketToNetwork returns negative errno.
|
||||
throw new ErrnoException("Binding socket to network " + netId, -err)
|
||||
.rethrowAsSocketException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Network} object given a handle returned from {@link #getNetworkHandle}.
|
||||
*
|
||||
* @param networkHandle a handle returned from {@link #getNetworkHandle}.
|
||||
* @return A {@link Network} object derived from {@code networkHandle}.
|
||||
*/
|
||||
public static Network fromNetworkHandle(long networkHandle) {
|
||||
if (networkHandle == 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Network.fromNetworkHandle refusing to instantiate NETID_UNSET Network.");
|
||||
}
|
||||
if ((networkHandle & ((1L << HANDLE_MAGIC_SIZE) - 1)) != HANDLE_MAGIC
|
||||
|| networkHandle < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Value passed to fromNetworkHandle() is not a network handle.");
|
||||
}
|
||||
return new Network((int) (networkHandle >> HANDLE_MAGIC_SIZE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a handle representing this {@code Network}, for use with the NDK API.
|
||||
*/
|
||||
public long getNetworkHandle() {
|
||||
// The network handle is explicitly not the same as the netId.
|
||||
//
|
||||
// The netId is an implementation detail which might be changed in the
|
||||
// future, or which alone (i.e. in the absence of some additional
|
||||
// context) might not be sufficient to fully identify a Network.
|
||||
//
|
||||
// As such, the intention is to prevent accidental misuse of the API
|
||||
// that might result if a developer assumed that handles and netIds
|
||||
// were identical and passing a netId to a call expecting a handle
|
||||
// "just worked". Such accidental misuse, if widely deployed, might
|
||||
// prevent future changes to the semantics of the netId field or
|
||||
// inhibit the expansion of state required for Network objects.
|
||||
//
|
||||
// This extra layer of indirection might be seen as paranoia, and might
|
||||
// never end up being necessary, but the added complexity is trivial.
|
||||
// At some future date it may be desirable to realign the handle with
|
||||
// Multiple Provisioning Domains API recommendations, as made by the
|
||||
// IETF mif working group.
|
||||
if (netId == 0) {
|
||||
return 0L; // make this zero condition obvious for debugging
|
||||
}
|
||||
return (((long) netId) << HANDLE_MAGIC_SIZE) | HANDLE_MAGIC;
|
||||
}
|
||||
|
||||
// implement the Parcelable interface
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(netId);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<Network> CREATOR =
|
||||
new Creator<Network>() {
|
||||
public Network createFromParcel(Parcel in) {
|
||||
int netId = in.readInt();
|
||||
|
||||
return new Network(netId);
|
||||
}
|
||||
|
||||
public Network[] newArray(int size) {
|
||||
return new Network[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Network)) return false;
|
||||
Network other = (Network)obj;
|
||||
return this.netId == other.netId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return netId * 11;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Integer.toString(netId);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(NetworkProto.NET_ID, netId);
|
||||
proto.end(token);
|
||||
}
|
||||
}
|
||||
1185
framework/src/android/net/NetworkAgent.java
Normal file
1185
framework/src/android/net/NetworkAgent.java
Normal file
File diff suppressed because it is too large
Load Diff
19
framework/src/android/net/NetworkAgentConfig.aidl
Normal file
19
framework/src/android/net/NetworkAgentConfig.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
parcelable NetworkAgentConfig;
|
||||
440
framework/src/android/net/NetworkAgentConfig.java
Normal file
440
framework/src/android/net/NetworkAgentConfig.java
Normal file
@@ -0,0 +1,440 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Allows a network transport to provide the system with policy and configuration information about
|
||||
* a particular network when registering a {@link NetworkAgent}. This information cannot change once the agent is registered.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class NetworkAgentConfig implements Parcelable {
|
||||
|
||||
/**
|
||||
* If the {@link Network} is a VPN, whether apps are allowed to bypass the
|
||||
* VPN. This is set by a {@link VpnService} and used by
|
||||
* {@link ConnectivityManager} when creating a VPN.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean allowBypass;
|
||||
|
||||
/**
|
||||
* Set if the network was manually/explicitly connected to by the user either from settings
|
||||
* or a 3rd party app. For example, turning on cell data is not explicit but tapping on a wifi
|
||||
* ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to
|
||||
* connect to a particular access point is also explicit, though this may change in the future
|
||||
* as we want apps to use the multinetwork apis.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean explicitlySelected;
|
||||
|
||||
/**
|
||||
* @return whether this network was explicitly selected by the user.
|
||||
*/
|
||||
public boolean isExplicitlySelected() {
|
||||
return explicitlySelected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the user desires to use this network even if it is unvalidated. This field has meaning
|
||||
* only if {@link explicitlySelected} is true. If it is, this field must also be set to the
|
||||
* appropriate value based on previous user choice.
|
||||
*
|
||||
* TODO : rename this field to match its accessor
|
||||
* @hide
|
||||
*/
|
||||
public boolean acceptUnvalidated;
|
||||
|
||||
/**
|
||||
* @return whether the system should accept this network even if it doesn't validate.
|
||||
*/
|
||||
public boolean isUnvalidatedConnectivityAcceptable() {
|
||||
return acceptUnvalidated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the user explicitly set that this network should be validated even if presence of
|
||||
* only partial internet connectivity.
|
||||
*
|
||||
* TODO : rename this field to match its accessor
|
||||
* @hide
|
||||
*/
|
||||
public boolean acceptPartialConnectivity;
|
||||
|
||||
/**
|
||||
* @return whether the system should validate this network even if it only offers partial
|
||||
* Internet connectivity.
|
||||
*/
|
||||
public boolean isPartialConnectivityAcceptable() {
|
||||
return acceptPartialConnectivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to avoid surfacing the "Sign in to network" notification.
|
||||
* if carrier receivers/apps are registered to handle the carrier-specific provisioning
|
||||
* procedure, a carrier specific provisioning notification will be placed.
|
||||
* only one notification should be displayed. This field is set based on
|
||||
* which notification should be used for provisioning.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean provisioningNotificationDisabled;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return whether the sign in to network notification is enabled by this configuration.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isProvisioningNotificationEnabled() {
|
||||
return !provisioningNotificationDisabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* For mobile networks, this is the subscriber ID (such as IMSI).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public String subscriberId;
|
||||
|
||||
/**
|
||||
* @return the subscriber ID, or null if none.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
@Nullable
|
||||
public String getSubscriberId() {
|
||||
return subscriberId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to skip 464xlat. This means the device will treat the network as IPv6-only and
|
||||
* will not attempt to detect a NAT64 via RFC 7050 DNS lookups.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean skip464xlat;
|
||||
|
||||
/**
|
||||
* @return whether NAT64 prefix detection is enabled.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isNat64DetectionEnabled() {
|
||||
return !skip464xlat;
|
||||
}
|
||||
|
||||
/**
|
||||
* The legacy type of this network agent, or TYPE_NONE if unset.
|
||||
* @hide
|
||||
*/
|
||||
public int legacyType = ConnectivityManager.TYPE_NONE;
|
||||
|
||||
/**
|
||||
* @return the legacy type
|
||||
*/
|
||||
@ConnectivityManager.LegacyNetworkType
|
||||
public int getLegacyType() {
|
||||
return legacyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network.
|
||||
* Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode.
|
||||
*
|
||||
* This is not parceled, because it would not make sense.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public transient boolean hasShownBroken;
|
||||
|
||||
/**
|
||||
* The name of the legacy network type. It's a free-form string used in logging.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public String legacyTypeName = "";
|
||||
|
||||
/**
|
||||
* @return the name of the legacy network type. It's a free-form string used in logging.
|
||||
*/
|
||||
@NonNull
|
||||
public String getLegacyTypeName() {
|
||||
return legacyTypeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The legacy extra info of the agent. The extra info should only be :
|
||||
* <ul>
|
||||
* <li>For cellular agents, the APN name.</li>
|
||||
* <li>For ethernet agents, the interface name.</li>
|
||||
* </ul>
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
private String mLegacyExtraInfo = "";
|
||||
|
||||
/**
|
||||
* The legacy extra info of the agent.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public String getLegacyExtraInfo() {
|
||||
return mLegacyExtraInfo;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public NetworkAgentConfig() {
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public NetworkAgentConfig(@Nullable NetworkAgentConfig nac) {
|
||||
if (nac != null) {
|
||||
allowBypass = nac.allowBypass;
|
||||
explicitlySelected = nac.explicitlySelected;
|
||||
acceptUnvalidated = nac.acceptUnvalidated;
|
||||
acceptPartialConnectivity = nac.acceptPartialConnectivity;
|
||||
subscriberId = nac.subscriberId;
|
||||
provisioningNotificationDisabled = nac.provisioningNotificationDisabled;
|
||||
skip464xlat = nac.skip464xlat;
|
||||
legacyType = nac.legacyType;
|
||||
legacyTypeName = nac.legacyTypeName;
|
||||
mLegacyExtraInfo = nac.mLegacyExtraInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class to facilitate constructing {@link NetworkAgentConfig} objects.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private final NetworkAgentConfig mConfig = new NetworkAgentConfig();
|
||||
|
||||
/**
|
||||
* Sets whether the network was explicitly selected by the user.
|
||||
*
|
||||
* @return this builder, to facilitate chaining.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setExplicitlySelected(final boolean explicitlySelected) {
|
||||
mConfig.explicitlySelected = explicitlySelected;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the system should validate this network even if it is found not to offer
|
||||
* Internet connectivity.
|
||||
*
|
||||
* @return this builder, to facilitate chaining.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setUnvalidatedConnectivityAcceptable(
|
||||
final boolean unvalidatedConnectivityAcceptable) {
|
||||
mConfig.acceptUnvalidated = unvalidatedConnectivityAcceptable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the system should validate this network even if it is found to only offer
|
||||
* partial Internet connectivity.
|
||||
*
|
||||
* @return this builder, to facilitate chaining.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setPartialConnectivityAcceptable(
|
||||
final boolean partialConnectivityAcceptable) {
|
||||
mConfig.acceptPartialConnectivity = partialConnectivityAcceptable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subscriber ID for this network.
|
||||
*
|
||||
* @return this builder, to facilitate chaining.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
public Builder setSubscriberId(@Nullable String subscriberId) {
|
||||
mConfig.subscriberId = subscriberId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables active detection of NAT64 (e.g., via RFC 7050 DNS lookups). Used to save power
|
||||
* and reduce idle traffic on networks that are known to be IPv6-only without a NAT64.
|
||||
*
|
||||
* @return this builder, to facilitate chaining.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public Builder disableNat64Detection() {
|
||||
mConfig.skip464xlat = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the "Sign in to network" notification. Used if the network transport will
|
||||
* perform its own carrier-specific provisioning procedure.
|
||||
*
|
||||
* @return this builder, to facilitate chaining.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public Builder disableProvisioningNotification() {
|
||||
mConfig.provisioningNotificationDisabled = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the legacy type for this network.
|
||||
*
|
||||
* @param legacyType the type
|
||||
* @return this builder, to facilitate chaining.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setLegacyType(int legacyType) {
|
||||
mConfig.legacyType = legacyType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the legacy type of the agent. It's a free-form string used in logging.
|
||||
* @param legacyTypeName the name
|
||||
* @return this builder, to facilitate chaining.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setLegacyTypeName(@NonNull String legacyTypeName) {
|
||||
mConfig.legacyTypeName = legacyTypeName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the legacy extra info of the agent.
|
||||
* @param legacyExtraInfo the legacy extra info.
|
||||
* @return this builder, to facilitate chaining.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) {
|
||||
mConfig.mLegacyExtraInfo = legacyExtraInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the constructed {@link NetworkAgentConfig} object.
|
||||
*/
|
||||
@NonNull
|
||||
public NetworkAgentConfig build() {
|
||||
return mConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final NetworkAgentConfig that = (NetworkAgentConfig) o;
|
||||
return allowBypass == that.allowBypass
|
||||
&& explicitlySelected == that.explicitlySelected
|
||||
&& acceptUnvalidated == that.acceptUnvalidated
|
||||
&& acceptPartialConnectivity == that.acceptPartialConnectivity
|
||||
&& provisioningNotificationDisabled == that.provisioningNotificationDisabled
|
||||
&& skip464xlat == that.skip464xlat
|
||||
&& legacyType == that.legacyType
|
||||
&& Objects.equals(subscriberId, that.subscriberId)
|
||||
&& Objects.equals(legacyTypeName, that.legacyTypeName)
|
||||
&& Objects.equals(mLegacyExtraInfo, that.mLegacyExtraInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(allowBypass, explicitlySelected, acceptUnvalidated,
|
||||
acceptPartialConnectivity, provisioningNotificationDisabled, subscriberId,
|
||||
skip464xlat, legacyType, legacyTypeName, mLegacyExtraInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NetworkAgentConfig {"
|
||||
+ " allowBypass = " + allowBypass
|
||||
+ ", explicitlySelected = " + explicitlySelected
|
||||
+ ", acceptUnvalidated = " + acceptUnvalidated
|
||||
+ ", acceptPartialConnectivity = " + acceptPartialConnectivity
|
||||
+ ", provisioningNotificationDisabled = " + provisioningNotificationDisabled
|
||||
+ ", subscriberId = '" + subscriberId + '\''
|
||||
+ ", skip464xlat = " + skip464xlat
|
||||
+ ", legacyType = " + legacyType
|
||||
+ ", hasShownBroken = " + hasShownBroken
|
||||
+ ", legacyTypeName = '" + legacyTypeName + '\''
|
||||
+ ", legacyExtraInfo = '" + mLegacyExtraInfo + '\''
|
||||
+ "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel out, int flags) {
|
||||
out.writeInt(allowBypass ? 1 : 0);
|
||||
out.writeInt(explicitlySelected ? 1 : 0);
|
||||
out.writeInt(acceptUnvalidated ? 1 : 0);
|
||||
out.writeInt(acceptPartialConnectivity ? 1 : 0);
|
||||
out.writeString(subscriberId);
|
||||
out.writeInt(provisioningNotificationDisabled ? 1 : 0);
|
||||
out.writeInt(skip464xlat ? 1 : 0);
|
||||
out.writeInt(legacyType);
|
||||
out.writeString(legacyTypeName);
|
||||
out.writeString(mLegacyExtraInfo);
|
||||
}
|
||||
|
||||
public static final @NonNull Creator<NetworkAgentConfig> CREATOR =
|
||||
new Creator<NetworkAgentConfig>() {
|
||||
@Override
|
||||
public NetworkAgentConfig createFromParcel(Parcel in) {
|
||||
NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig();
|
||||
networkAgentConfig.allowBypass = in.readInt() != 0;
|
||||
networkAgentConfig.explicitlySelected = in.readInt() != 0;
|
||||
networkAgentConfig.acceptUnvalidated = in.readInt() != 0;
|
||||
networkAgentConfig.acceptPartialConnectivity = in.readInt() != 0;
|
||||
networkAgentConfig.subscriberId = in.readString();
|
||||
networkAgentConfig.provisioningNotificationDisabled = in.readInt() != 0;
|
||||
networkAgentConfig.skip464xlat = in.readInt() != 0;
|
||||
networkAgentConfig.legacyType = in.readInt();
|
||||
networkAgentConfig.legacyTypeName = in.readString();
|
||||
networkAgentConfig.mLegacyExtraInfo = in.readString();
|
||||
return networkAgentConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkAgentConfig[] newArray(int size) {
|
||||
return new NetworkAgentConfig[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
21
framework/src/android/net/NetworkCapabilities.aidl
Normal file
21
framework/src/android/net/NetworkCapabilities.aidl
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2014 The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable NetworkCapabilities;
|
||||
|
||||
2517
framework/src/android/net/NetworkCapabilities.java
Normal file
2517
framework/src/android/net/NetworkCapabilities.java
Normal file
File diff suppressed because it is too large
Load Diff
80
framework/src/android/net/NetworkConfig.java
Normal file
80
framework/src/android/net/NetworkConfig.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Describes the buildtime configuration of a network.
|
||||
* Holds settings read from resources.
|
||||
* @hide
|
||||
*/
|
||||
public class NetworkConfig {
|
||||
/**
|
||||
* Human readable string
|
||||
*/
|
||||
public String name;
|
||||
|
||||
/**
|
||||
* Type from ConnectivityManager
|
||||
*/
|
||||
public int type;
|
||||
|
||||
/**
|
||||
* the radio number from radio attributes config
|
||||
*/
|
||||
public int radio;
|
||||
|
||||
/**
|
||||
* higher number == higher priority when turning off connections
|
||||
*/
|
||||
public int priority;
|
||||
|
||||
/**
|
||||
* indicates the boot time dependencyMet setting
|
||||
*/
|
||||
public boolean dependencyMet;
|
||||
|
||||
/**
|
||||
* indicates the default restoral timer in seconds
|
||||
* if the network is used as a special network feature
|
||||
* -1 indicates no restoration of default
|
||||
*/
|
||||
public int restoreTime;
|
||||
|
||||
/**
|
||||
* input string from config.xml resource. Uses the form:
|
||||
* [Connection name],[ConnectivityManager connection type],
|
||||
* [associated radio-type],[priority],[dependencyMet]
|
||||
*/
|
||||
public NetworkConfig(String init) {
|
||||
String fragments[] = init.split(",");
|
||||
name = fragments[0].trim().toLowerCase(Locale.ROOT);
|
||||
type = Integer.parseInt(fragments[1]);
|
||||
radio = Integer.parseInt(fragments[2]);
|
||||
priority = Integer.parseInt(fragments[3]);
|
||||
restoreTime = Integer.parseInt(fragments[4]);
|
||||
dependencyMet = Boolean.parseBoolean(fragments[5]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this network is supposed to be default-routable
|
||||
*/
|
||||
public boolean isDefault() {
|
||||
return (type == radio);
|
||||
}
|
||||
}
|
||||
19
framework/src/android/net/NetworkInfo.aidl
Normal file
19
framework/src/android/net/NetworkInfo.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2007, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
parcelable NetworkInfo;
|
||||
626
framework/src/android/net/NetworkInfo.java
Normal file
626
framework/src/android/net/NetworkInfo.java
Normal file
@@ -0,0 +1,626 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.telephony.Annotation.NetworkType;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.EnumMap;
|
||||
|
||||
/**
|
||||
* Describes the status of a network interface.
|
||||
* <p>Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents
|
||||
* the current network connection.
|
||||
*
|
||||
* @deprecated Callers should instead use the {@link ConnectivityManager.NetworkCallback} API to
|
||||
* learn about connectivity changes, or switch to use
|
||||
* {@link ConnectivityManager#getNetworkCapabilities} or
|
||||
* {@link ConnectivityManager#getLinkProperties} to get information synchronously. Keep
|
||||
* in mind that while callbacks are guaranteed to be called for every event in order,
|
||||
* synchronous calls have no such constraints, and as such it is unadvisable to use the
|
||||
* synchronous methods inside the callbacks as they will often not offer a view of
|
||||
* networking that is consistent (that is: they may return a past or a future state with
|
||||
* respect to the event being processed by the callback). Instead, callers are advised
|
||||
* to only use the arguments of the callbacks, possibly memorizing the specific bits of
|
||||
* information they need to keep from one callback to another.
|
||||
*/
|
||||
@Deprecated
|
||||
public class NetworkInfo implements Parcelable {
|
||||
|
||||
/**
|
||||
* Coarse-grained network state. This is probably what most applications should
|
||||
* use, rather than {@link android.net.NetworkInfo.DetailedState DetailedState}.
|
||||
* The mapping between the two is as follows:
|
||||
* <br/><br/>
|
||||
* <table>
|
||||
* <tr><td><b>Detailed state</b></td><td><b>Coarse-grained state</b></td></tr>
|
||||
* <tr><td><code>IDLE</code></td><td><code>DISCONNECTED</code></td></tr>
|
||||
* <tr><td><code>SCANNING</code></td><td><code>DISCONNECTED</code></td></tr>
|
||||
* <tr><td><code>CONNECTING</code></td><td><code>CONNECTING</code></td></tr>
|
||||
* <tr><td><code>AUTHENTICATING</code></td><td><code>CONNECTING</code></td></tr>
|
||||
* <tr><td><code>OBTAINING_IPADDR</code></td><td><code>CONNECTING</code></td></tr>
|
||||
* <tr><td><code>VERIFYING_POOR_LINK</code></td><td><code>CONNECTING</code></td></tr>
|
||||
* <tr><td><code>CAPTIVE_PORTAL_CHECK</code></td><td><code>CONNECTING</code></td></tr>
|
||||
* <tr><td><code>CONNECTED</code></td><td><code>CONNECTED</code></td></tr>
|
||||
* <tr><td><code>SUSPENDED</code></td><td><code>SUSPENDED</code></td></tr>
|
||||
* <tr><td><code>DISCONNECTING</code></td><td><code>DISCONNECTING</code></td></tr>
|
||||
* <tr><td><code>DISCONNECTED</code></td><td><code>DISCONNECTED</code></td></tr>
|
||||
* <tr><td><code>FAILED</code></td><td><code>DISCONNECTED</code></td></tr>
|
||||
* <tr><td><code>BLOCKED</code></td><td><code>DISCONNECTED</code></td></tr>
|
||||
* </table>
|
||||
*
|
||||
* @deprecated See {@link NetworkInfo}.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum State {
|
||||
CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN
|
||||
}
|
||||
|
||||
/**
|
||||
* The fine-grained state of a network connection. This level of detail
|
||||
* is probably of interest to few applications. Most should use
|
||||
* {@link android.net.NetworkInfo.State State} instead.
|
||||
*
|
||||
* @deprecated See {@link NetworkInfo}.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum DetailedState {
|
||||
/** Ready to start data connection setup. */
|
||||
IDLE,
|
||||
/** Searching for an available access point. */
|
||||
SCANNING,
|
||||
/** Currently setting up data connection. */
|
||||
CONNECTING,
|
||||
/** Network link established, performing authentication. */
|
||||
AUTHENTICATING,
|
||||
/** Awaiting response from DHCP server in order to assign IP address information. */
|
||||
OBTAINING_IPADDR,
|
||||
/** IP traffic should be available. */
|
||||
CONNECTED,
|
||||
/** IP traffic is suspended */
|
||||
SUSPENDED,
|
||||
/** Currently tearing down data connection. */
|
||||
DISCONNECTING,
|
||||
/** IP traffic not available. */
|
||||
DISCONNECTED,
|
||||
/** Attempt to connect failed. */
|
||||
FAILED,
|
||||
/** Access to this network is blocked. */
|
||||
BLOCKED,
|
||||
/** Link has poor connectivity. */
|
||||
VERIFYING_POOR_LINK,
|
||||
/** Checking if network is a captive portal */
|
||||
CAPTIVE_PORTAL_CHECK
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the map described in the Javadoc comment above. The positions
|
||||
* of the elements of the array must correspond to the ordinal values
|
||||
* of <code>DetailedState</code>.
|
||||
*/
|
||||
private static final EnumMap<DetailedState, State> stateMap =
|
||||
new EnumMap<DetailedState, State>(DetailedState.class);
|
||||
|
||||
static {
|
||||
stateMap.put(DetailedState.IDLE, State.DISCONNECTED);
|
||||
stateMap.put(DetailedState.SCANNING, State.DISCONNECTED);
|
||||
stateMap.put(DetailedState.CONNECTING, State.CONNECTING);
|
||||
stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING);
|
||||
stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING);
|
||||
stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING);
|
||||
stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING);
|
||||
stateMap.put(DetailedState.CONNECTED, State.CONNECTED);
|
||||
stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED);
|
||||
stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING);
|
||||
stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
|
||||
stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
|
||||
stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED);
|
||||
}
|
||||
|
||||
private int mNetworkType;
|
||||
private int mSubtype;
|
||||
private String mTypeName;
|
||||
private String mSubtypeName;
|
||||
@NonNull
|
||||
private State mState;
|
||||
@NonNull
|
||||
private DetailedState mDetailedState;
|
||||
private String mReason;
|
||||
private String mExtraInfo;
|
||||
private boolean mIsFailover;
|
||||
private boolean mIsAvailable;
|
||||
private boolean mIsRoaming;
|
||||
|
||||
/**
|
||||
* Create a new instance of NetworkInfo.
|
||||
*
|
||||
* This may be useful for apps to write unit tests.
|
||||
*
|
||||
* @param type the legacy type of the network, as one of the ConnectivityManager.TYPE_*
|
||||
* constants.
|
||||
* @param subtype the subtype if applicable, as one of the TelephonyManager.NETWORK_TYPE_*
|
||||
* constants.
|
||||
* @param typeName a human-readable string for the network type, or an empty string or null.
|
||||
* @param subtypeName a human-readable string for the subtype, or an empty string or null.
|
||||
*/
|
||||
public NetworkInfo(int type, @NetworkType int subtype,
|
||||
@Nullable String typeName, @Nullable String subtypeName) {
|
||||
if (!ConnectivityManager.isNetworkTypeValid(type)
|
||||
&& type != ConnectivityManager.TYPE_NONE) {
|
||||
throw new IllegalArgumentException("Invalid network type: " + type);
|
||||
}
|
||||
mNetworkType = type;
|
||||
mSubtype = subtype;
|
||||
mTypeName = typeName;
|
||||
mSubtypeName = subtypeName;
|
||||
setDetailedState(DetailedState.IDLE, null, null);
|
||||
mState = State.UNKNOWN;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
@UnsupportedAppUsage
|
||||
public NetworkInfo(NetworkInfo source) {
|
||||
if (source != null) {
|
||||
synchronized (source) {
|
||||
mNetworkType = source.mNetworkType;
|
||||
mSubtype = source.mSubtype;
|
||||
mTypeName = source.mTypeName;
|
||||
mSubtypeName = source.mSubtypeName;
|
||||
mState = source.mState;
|
||||
mDetailedState = source.mDetailedState;
|
||||
mReason = source.mReason;
|
||||
mExtraInfo = source.mExtraInfo;
|
||||
mIsFailover = source.mIsFailover;
|
||||
mIsAvailable = source.mIsAvailable;
|
||||
mIsRoaming = source.mIsRoaming;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the type of network to which the
|
||||
* info in this {@code NetworkInfo} pertains.
|
||||
* @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link
|
||||
* ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link
|
||||
* ConnectivityManager#TYPE_ETHERNET}, {@link ConnectivityManager#TYPE_BLUETOOTH}, or other
|
||||
* types defined by {@link ConnectivityManager}.
|
||||
* @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
|
||||
* instead with one of the NetworkCapabilities#TRANSPORT_* constants :
|
||||
* {@link #getType} and {@link #getTypeName} cannot account for networks using
|
||||
* multiple transports. Note that generally apps should not care about transport;
|
||||
* {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
|
||||
* {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
|
||||
* apps concerned with meteredness or bandwidth should be looking at, as they
|
||||
* offer this information with much better accuracy.
|
||||
*/
|
||||
@Deprecated
|
||||
public int getType() {
|
||||
synchronized (this) {
|
||||
return mNetworkType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link NetworkCapabilities} instead
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
public void setType(int type) {
|
||||
synchronized (this) {
|
||||
mNetworkType = type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a network-type-specific integer describing the subtype
|
||||
* of the network.
|
||||
* @return the network subtype
|
||||
* @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public int getSubtype() {
|
||||
synchronized (this) {
|
||||
return mSubtype;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public void setSubtype(int subtype, String subtypeName) {
|
||||
synchronized (this) {
|
||||
mSubtype = subtype;
|
||||
mSubtypeName = subtypeName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a human-readable name describe the type of the network,
|
||||
* for example "WIFI" or "MOBILE".
|
||||
* @return the name of the network type
|
||||
* @deprecated Callers should switch to checking {@link NetworkCapabilities#hasTransport}
|
||||
* instead with one of the NetworkCapabilities#TRANSPORT_* constants :
|
||||
* {@link #getType} and {@link #getTypeName} cannot account for networks using
|
||||
* multiple transports. Note that generally apps should not care about transport;
|
||||
* {@link NetworkCapabilities#NET_CAPABILITY_NOT_METERED} and
|
||||
* {@link NetworkCapabilities#getLinkDownstreamBandwidthKbps} are calls that
|
||||
* apps concerned with meteredness or bandwidth should be looking at, as they
|
||||
* offer this information with much better accuracy.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getTypeName() {
|
||||
synchronized (this) {
|
||||
return mTypeName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a human-readable name describing the subtype of the network.
|
||||
* @return the name of the network subtype
|
||||
* @deprecated Use {@link android.telephony.TelephonyManager#getDataNetworkType} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getSubtypeName() {
|
||||
synchronized (this) {
|
||||
return mSubtypeName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether network connectivity exists or is in the process
|
||||
* of being established. This is good for applications that need to
|
||||
* do anything related to the network other than read or write data.
|
||||
* For the latter, call {@link #isConnected()} instead, which guarantees
|
||||
* that the network is fully usable.
|
||||
* @return {@code true} if network connectivity exists or is in the process
|
||||
* of being established, {@code false} otherwise.
|
||||
* @deprecated Apps should instead use the
|
||||
* {@link android.net.ConnectivityManager.NetworkCallback} API to
|
||||
* learn about connectivity changes.
|
||||
* {@link ConnectivityManager#registerDefaultNetworkCallback} and
|
||||
* {@link ConnectivityManager#registerNetworkCallback}. These will
|
||||
* give a more accurate picture of the connectivity state of
|
||||
* the device and let apps react more easily and quickly to changes.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isConnectedOrConnecting() {
|
||||
synchronized (this) {
|
||||
return mState == State.CONNECTED || mState == State.CONNECTING;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether network connectivity exists and it is possible to establish
|
||||
* connections and pass data.
|
||||
* <p>Always call this before attempting to perform data transactions.
|
||||
* @return {@code true} if network connectivity exists, {@code false} otherwise.
|
||||
* @deprecated Apps should instead use the
|
||||
* {@link android.net.ConnectivityManager.NetworkCallback} API to
|
||||
* learn about connectivity changes. See
|
||||
* {@link ConnectivityManager#registerDefaultNetworkCallback} and
|
||||
* {@link ConnectivityManager#registerNetworkCallback}. These will
|
||||
* give a more accurate picture of the connectivity state of
|
||||
* the device and let apps react more easily and quickly to changes.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isConnected() {
|
||||
synchronized (this) {
|
||||
return mState == State.CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether network connectivity is possible. A network is unavailable
|
||||
* when a persistent or semi-persistent condition prevents the possibility
|
||||
* of connecting to that network. Examples include
|
||||
* <ul>
|
||||
* <li>The device is out of the coverage area for any network of this type.</li>
|
||||
* <li>The device is on a network other than the home network (i.e., roaming), and
|
||||
* data roaming has been disabled.</li>
|
||||
* <li>The device's radio is turned off, e.g., because airplane mode is enabled.</li>
|
||||
* </ul>
|
||||
* Since Android L, this always returns {@code true}, because the system only
|
||||
* returns info for available networks.
|
||||
* @return {@code true} if the network is available, {@code false} otherwise
|
||||
* @deprecated Apps should instead use the
|
||||
* {@link android.net.ConnectivityManager.NetworkCallback} API to
|
||||
* learn about connectivity changes.
|
||||
* {@link ConnectivityManager#registerDefaultNetworkCallback} and
|
||||
* {@link ConnectivityManager#registerNetworkCallback}. These will
|
||||
* give a more accurate picture of the connectivity state of
|
||||
* the device and let apps react more easily and quickly to changes.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isAvailable() {
|
||||
synchronized (this) {
|
||||
return mIsAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the network is available, ie, if the connectivity is possible.
|
||||
* @param isAvailable the new availability value.
|
||||
* @deprecated Use {@link NetworkCapabilities} instead
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@UnsupportedAppUsage
|
||||
public void setIsAvailable(boolean isAvailable) {
|
||||
synchronized (this) {
|
||||
mIsAvailable = isAvailable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the current attempt to connect to the network
|
||||
* resulted from the ConnectivityManager trying to fail over to this
|
||||
* network following a disconnect from another network.
|
||||
* @return {@code true} if this is a failover attempt, {@code false}
|
||||
* otherwise.
|
||||
* @deprecated This field is not populated in recent Android releases,
|
||||
* and does not make a lot of sense in a multi-network world.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isFailover() {
|
||||
synchronized (this) {
|
||||
return mIsFailover;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the failover boolean.
|
||||
* @param isFailover {@code true} to mark the current connection attempt
|
||||
* as a failover.
|
||||
* @deprecated This hasn't been set in any recent Android release.
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@UnsupportedAppUsage
|
||||
public void setFailover(boolean isFailover) {
|
||||
synchronized (this) {
|
||||
mIsFailover = isFailover;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the device is currently roaming on this network. When
|
||||
* {@code true}, it suggests that use of data on this network may incur
|
||||
* extra costs.
|
||||
*
|
||||
* @return {@code true} if roaming is in effect, {@code false} otherwise.
|
||||
* @deprecated Callers should switch to checking
|
||||
* {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING}
|
||||
* instead, since that handles more complex situations, such as
|
||||
* VPNs.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isRoaming() {
|
||||
synchronized (this) {
|
||||
return mIsRoaming;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING} instead.
|
||||
* {@hide}
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Deprecated
|
||||
@UnsupportedAppUsage
|
||||
public void setRoaming(boolean isRoaming) {
|
||||
synchronized (this) {
|
||||
mIsRoaming = isRoaming;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the current coarse-grained state of the network.
|
||||
* @return the coarse-grained state
|
||||
* @deprecated Apps should instead use the
|
||||
* {@link android.net.ConnectivityManager.NetworkCallback} API to
|
||||
* learn about connectivity changes.
|
||||
* {@link ConnectivityManager#registerDefaultNetworkCallback} and
|
||||
* {@link ConnectivityManager#registerNetworkCallback}. These will
|
||||
* give a more accurate picture of the connectivity state of
|
||||
* the device and let apps react more easily and quickly to changes.
|
||||
*/
|
||||
@Deprecated
|
||||
public State getState() {
|
||||
synchronized (this) {
|
||||
return mState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the current fine-grained state of the network.
|
||||
* @return the fine-grained state
|
||||
* @deprecated Apps should instead use the
|
||||
* {@link android.net.ConnectivityManager.NetworkCallback} API to
|
||||
* learn about connectivity changes. See
|
||||
* {@link ConnectivityManager#registerDefaultNetworkCallback} and
|
||||
* {@link ConnectivityManager#registerNetworkCallback}. These will
|
||||
* give a more accurate picture of the connectivity state of
|
||||
* the device and let apps react more easily and quickly to changes.
|
||||
*/
|
||||
@Deprecated
|
||||
public @NonNull DetailedState getDetailedState() {
|
||||
synchronized (this) {
|
||||
return mDetailedState;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the fine-grained state of the network.
|
||||
*
|
||||
* This is only useful for testing.
|
||||
*
|
||||
* @param detailedState the {@link DetailedState}.
|
||||
* @param reason a {@code String} indicating the reason for the state change,
|
||||
* if one was supplied. May be {@code null}.
|
||||
* @param extraInfo an optional {@code String} providing addditional network state
|
||||
* information passed up from the lower networking layers.
|
||||
* @deprecated Use {@link NetworkCapabilities} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDetailedState(@NonNull DetailedState detailedState, @Nullable String reason,
|
||||
@Nullable String extraInfo) {
|
||||
synchronized (this) {
|
||||
this.mDetailedState = detailedState;
|
||||
this.mState = stateMap.get(detailedState);
|
||||
this.mReason = reason;
|
||||
this.mExtraInfo = extraInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the extraInfo field.
|
||||
* @param extraInfo an optional {@code String} providing addditional network state
|
||||
* information passed up from the lower networking layers.
|
||||
* @deprecated See {@link NetworkInfo#getExtraInfo}.
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
public void setExtraInfo(String extraInfo) {
|
||||
synchronized (this) {
|
||||
this.mExtraInfo = extraInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the reason an attempt to establish connectivity failed,
|
||||
* if one is available.
|
||||
* @return the reason for failure, or null if not available
|
||||
* @deprecated This method does not have a consistent contract that could make it useful
|
||||
* to callers.
|
||||
*/
|
||||
public String getReason() {
|
||||
synchronized (this) {
|
||||
return mReason;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the extra information about the network state, if any was
|
||||
* provided by the lower networking layers.
|
||||
* @return the extra information, or null if not available
|
||||
* @deprecated Use other services e.g. WifiManager to get additional information passed up from
|
||||
* the lower networking layers.
|
||||
*/
|
||||
@Deprecated
|
||||
public String getExtraInfo() {
|
||||
synchronized (this) {
|
||||
return mExtraInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
synchronized (this) {
|
||||
final StringBuilder builder = new StringBuilder("[");
|
||||
builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()).
|
||||
append("], state: ").append(mState).append("/").append(mDetailedState).
|
||||
append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
|
||||
append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
|
||||
append(", failover: ").append(mIsFailover).
|
||||
append(", available: ").append(mIsAvailable).
|
||||
append(", roaming: ").append(mIsRoaming).
|
||||
append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a brief summary string suitable for debugging.
|
||||
* @hide
|
||||
*/
|
||||
public String toShortString() {
|
||||
synchronized (this) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append(getTypeName());
|
||||
|
||||
final String subtype = getSubtypeName();
|
||||
if (!TextUtils.isEmpty(subtype)) {
|
||||
builder.append("[").append(subtype).append("]");
|
||||
}
|
||||
|
||||
builder.append(" ");
|
||||
builder.append(mDetailedState);
|
||||
if (mIsRoaming) {
|
||||
builder.append(" ROAMING");
|
||||
}
|
||||
if (mExtraInfo != null) {
|
||||
builder.append(" extra: ").append(mExtraInfo);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
synchronized (this) {
|
||||
dest.writeInt(mNetworkType);
|
||||
dest.writeInt(mSubtype);
|
||||
dest.writeString(mTypeName);
|
||||
dest.writeString(mSubtypeName);
|
||||
dest.writeString(mState.name());
|
||||
dest.writeString(mDetailedState.name());
|
||||
dest.writeInt(mIsFailover ? 1 : 0);
|
||||
dest.writeInt(mIsAvailable ? 1 : 0);
|
||||
dest.writeInt(mIsRoaming ? 1 : 0);
|
||||
dest.writeString(mReason);
|
||||
dest.writeString(mExtraInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() {
|
||||
@Override
|
||||
public NetworkInfo createFromParcel(Parcel in) {
|
||||
int netType = in.readInt();
|
||||
int subtype = in.readInt();
|
||||
String typeName = in.readString();
|
||||
String subtypeName = in.readString();
|
||||
NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName);
|
||||
netInfo.mState = State.valueOf(in.readString());
|
||||
netInfo.mDetailedState = DetailedState.valueOf(in.readString());
|
||||
netInfo.mIsFailover = in.readInt() != 0;
|
||||
netInfo.mIsAvailable = in.readInt() != 0;
|
||||
netInfo.mIsRoaming = in.readInt() != 0;
|
||||
netInfo.mReason = in.readString();
|
||||
netInfo.mExtraInfo = in.readString();
|
||||
return netInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkInfo[] newArray(int size) {
|
||||
return new NetworkInfo[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
162
framework/src/android/net/NetworkProvider.java
Normal file
162
framework/src/android/net/NetworkProvider.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device
|
||||
* to networks and makes them available to the core network stack by creating
|
||||
* {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted
|
||||
* with via networking APIs such as {@link ConnectivityManager}.
|
||||
*
|
||||
* Subclasses should implement {@link #onNetworkRequested} and {@link #onNetworkRequestWithdrawn}
|
||||
* to receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the
|
||||
* best (highest-scoring) network for any request is generally not used by the system, and torn
|
||||
* down.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public class NetworkProvider {
|
||||
/**
|
||||
* {@code providerId} value that indicates the absence of a provider. It is the providerId of
|
||||
* any NetworkProvider that is not currently registered, and of any NetworkRequest that is not
|
||||
* currently being satisfied by a network.
|
||||
*/
|
||||
public static final int ID_NONE = -1;
|
||||
|
||||
/**
|
||||
* The first providerId value that will be allocated.
|
||||
* @hide only used by ConnectivityService.
|
||||
*/
|
||||
public static final int FIRST_PROVIDER_ID = 1;
|
||||
|
||||
/** @hide only used by ConnectivityService */
|
||||
public static final int CMD_REQUEST_NETWORK = 1;
|
||||
/** @hide only used by ConnectivityService */
|
||||
public static final int CMD_CANCEL_REQUEST = 2;
|
||||
|
||||
private final Messenger mMessenger;
|
||||
private final String mName;
|
||||
private final Context mContext;
|
||||
|
||||
private int mProviderId = ID_NONE;
|
||||
|
||||
/**
|
||||
* Constructs a new NetworkProvider.
|
||||
*
|
||||
* @param looper the Looper on which to run {@link #onNetworkRequested} and
|
||||
* {@link #onNetworkRequestWithdrawn}.
|
||||
* @param name the name of the listener, used only for debugging.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) {
|
||||
Handler handler = new Handler(looper) {
|
||||
@Override
|
||||
public void handleMessage(Message m) {
|
||||
switch (m.what) {
|
||||
case CMD_REQUEST_NETWORK:
|
||||
onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2);
|
||||
break;
|
||||
case CMD_CANCEL_REQUEST:
|
||||
onNetworkRequestWithdrawn((NetworkRequest) m.obj);
|
||||
break;
|
||||
default:
|
||||
Log.e(mName, "Unhandled message: " + m.what);
|
||||
}
|
||||
}
|
||||
};
|
||||
mContext = context;
|
||||
mMessenger = new Messenger(handler);
|
||||
mName = name;
|
||||
}
|
||||
|
||||
// TODO: consider adding a register() method so ConnectivityManager does not need to call this.
|
||||
/** @hide */
|
||||
public @Nullable Messenger getMessenger() {
|
||||
return mMessenger;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public @NonNull String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of this provider. This is known only once the provider is registered via
|
||||
* {@link ConnectivityManager#registerNetworkProvider()}, otherwise the ID is {@link #ID_NONE}.
|
||||
* This ID must be used when registering any {@link NetworkAgent}s.
|
||||
*/
|
||||
public int getProviderId() {
|
||||
return mProviderId;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setProviderId(int providerId) {
|
||||
mProviderId = providerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a NetworkRequest is received. The request may be a new request or an existing
|
||||
* request with a different score.
|
||||
*
|
||||
* @param request the NetworkRequest being received
|
||||
* @param score the score of the network currently satisfying the request, or 0 if none.
|
||||
* @param providerId the ID of the provider that created the network currently satisfying this
|
||||
* request, or {@link #ID_NONE} if none.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public void onNetworkRequested(@NonNull NetworkRequest request,
|
||||
@IntRange(from = 0, to = 99) int score, int providerId) {}
|
||||
|
||||
/**
|
||||
* Called when a NetworkRequest is withdrawn.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {}
|
||||
|
||||
/**
|
||||
* Asserts that no provider will ever be able to satisfy the specified request. The provider
|
||||
* must only call this method if it knows that it is the only provider on the system capable of
|
||||
* satisfying this request, and that the request cannot be satisfied. The application filing the
|
||||
* request will receive an {@link NetworkCallback#onUnavailable()} callback.
|
||||
*
|
||||
* @param request the request that permanently cannot be fulfilled
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
|
||||
public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
|
||||
ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request);
|
||||
}
|
||||
}
|
||||
20
framework/src/android/net/NetworkRequest.aidl
Normal file
20
framework/src/android/net/NetworkRequest.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2014, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
parcelable NetworkRequest;
|
||||
|
||||
582
framework/src/android/net/NetworkRequest.java
Normal file
582
framework/src/android/net/NetworkRequest.java
Normal file
@@ -0,0 +1,582 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.net.NetworkCapabilities.NetCapability;
|
||||
import android.net.NetworkCapabilities.Transport;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.text.TextUtils;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Defines a request for a network, made through {@link NetworkRequest.Builder} and used
|
||||
* to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes
|
||||
* via {@link ConnectivityManager#registerNetworkCallback}.
|
||||
*/
|
||||
public class NetworkRequest implements Parcelable {
|
||||
/**
|
||||
* The first requestId value that will be allocated.
|
||||
* @hide only used by ConnectivityService.
|
||||
*/
|
||||
public static final int FIRST_REQUEST_ID = 1;
|
||||
|
||||
/**
|
||||
* The requestId value that represents the absence of a request.
|
||||
* @hide only used by ConnectivityService.
|
||||
*/
|
||||
public static final int REQUEST_ID_NONE = -1;
|
||||
|
||||
/**
|
||||
* The {@link NetworkCapabilities} that define this request.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public final @NonNull NetworkCapabilities networkCapabilities;
|
||||
|
||||
/**
|
||||
* Identifies the request. NetworkRequests should only be constructed by
|
||||
* the Framework and given out to applications as tokens to be used to identify
|
||||
* the request.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public final int requestId;
|
||||
|
||||
/**
|
||||
* Set for legacy requests and the default. Set to TYPE_NONE for none.
|
||||
* Causes CONNECTIVITY_ACTION broadcasts to be sent.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||
public final int legacyType;
|
||||
|
||||
/**
|
||||
* A NetworkRequest as used by the system can be one of the following types:
|
||||
*
|
||||
* - LISTEN, for which the framework will issue callbacks about any
|
||||
* and all networks that match the specified NetworkCapabilities,
|
||||
*
|
||||
* - REQUEST, capable of causing a specific network to be created
|
||||
* first (e.g. a telephony DUN request), the framework will issue
|
||||
* callbacks about the single, highest scoring current network
|
||||
* (if any) that matches the specified NetworkCapabilities, or
|
||||
*
|
||||
* - TRACK_DEFAULT, a hybrid of the two designed such that the
|
||||
* framework will issue callbacks for the single, highest scoring
|
||||
* current network (if any) that matches the capabilities of the
|
||||
* default Internet request (mDefaultRequest), but which cannot cause
|
||||
* the framework to either create or retain the existence of any
|
||||
* specific network. Note that from the point of view of the request
|
||||
* matching code, TRACK_DEFAULT is identical to REQUEST: its special
|
||||
* behaviour is not due to different semantics, but to the fact that
|
||||
* the system will only ever create a TRACK_DEFAULT with capabilities
|
||||
* that are identical to the default request's capabilities, thus
|
||||
* causing it to share fate in every way with the default request.
|
||||
*
|
||||
* - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
|
||||
* to retain the NET_CAPABILITY_FOREGROUND capability. A network with
|
||||
* no foreground requests is in the background. A network that has
|
||||
* one or more background requests and loses its last foreground
|
||||
* request to a higher-scoring network will not go into the
|
||||
* background immediately, but will linger and go into the background
|
||||
* after the linger timeout.
|
||||
*
|
||||
* - The value NONE is used only by applications. When an application
|
||||
* creates a NetworkRequest, it does not have a type; the type is set
|
||||
* by the system depending on the method used to file the request
|
||||
* (requestNetwork, registerNetworkCallback, etc.).
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static enum Type {
|
||||
NONE,
|
||||
LISTEN,
|
||||
TRACK_DEFAULT,
|
||||
REQUEST,
|
||||
BACKGROUND_REQUEST,
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of the request. This is only used by the system and is always NONE elsewhere.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final Type type;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId, Type type) {
|
||||
if (nc == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
requestId = rId;
|
||||
networkCapabilities = nc;
|
||||
this.legacyType = legacyType;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public NetworkRequest(NetworkRequest that) {
|
||||
networkCapabilities = new NetworkCapabilities(that.networkCapabilities);
|
||||
requestId = that.requestId;
|
||||
this.legacyType = that.legacyType;
|
||||
this.type = that.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder used to create {@link NetworkRequest} objects. Specify the Network features
|
||||
* needed in terms of {@link NetworkCapabilities} features
|
||||
*/
|
||||
public static class Builder {
|
||||
private final NetworkCapabilities mNetworkCapabilities;
|
||||
|
||||
/**
|
||||
* Default constructor for Builder.
|
||||
*/
|
||||
public Builder() {
|
||||
// By default, restrict this request to networks available to this app.
|
||||
// Apps can rescind this restriction, but ConnectivityService will enforce
|
||||
// it for apps that do not have the NETWORK_SETTINGS permission.
|
||||
mNetworkCapabilities = new NetworkCapabilities();
|
||||
mNetworkCapabilities.setSingleUid(Process.myUid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Build {@link NetworkRequest} give the current set of capabilities.
|
||||
*/
|
||||
public NetworkRequest build() {
|
||||
// Make a copy of mNetworkCapabilities so we don't inadvertently remove NOT_RESTRICTED
|
||||
// when later an unrestricted capability could be added to mNetworkCapabilities, in
|
||||
// which case NOT_RESTRICTED should be returned to mNetworkCapabilities, which
|
||||
// maybeMarkCapabilitiesRestricted() doesn't add back.
|
||||
final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
|
||||
nc.maybeMarkCapabilitiesRestricted();
|
||||
return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
|
||||
ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given capability requirement to this builder. These represent
|
||||
* the requested network's required capabilities. Note that when searching
|
||||
* for a network to satisfy a request, all capabilities requested must be
|
||||
* satisfied.
|
||||
*
|
||||
* @param capability The capability to add.
|
||||
* @return The builder to facilitate chaining
|
||||
* {@code builder.addCapability(...).addCapability();}.
|
||||
*/
|
||||
public Builder addCapability(@NetworkCapabilities.NetCapability int capability) {
|
||||
mNetworkCapabilities.addCapability(capability);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes (if found) the given capability from this builder instance.
|
||||
*
|
||||
* @param capability The capability to remove.
|
||||
* @return The builder to facilitate chaining.
|
||||
*/
|
||||
public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) {
|
||||
mNetworkCapabilities.removeCapability(capability);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@code NetworkCapabilities} for this builder instance,
|
||||
* overriding any capabilities that had been previously set.
|
||||
*
|
||||
* @param nc The superseding {@code NetworkCapabilities} instance.
|
||||
* @return The builder to facilitate chaining.
|
||||
* @hide
|
||||
*/
|
||||
public Builder setCapabilities(NetworkCapabilities nc) {
|
||||
mNetworkCapabilities.set(nc);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the watched UIDs for this request. This will be reset and wiped out unless
|
||||
* the calling app holds the CHANGE_NETWORK_STATE permission.
|
||||
*
|
||||
* @param uids The watched UIDs as a set of UidRanges, or null for everything.
|
||||
* @return The builder to facilitate chaining.
|
||||
* @hide
|
||||
*/
|
||||
public Builder setUids(Set<UidRange> uids) {
|
||||
mNetworkCapabilities.setUids(uids);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a capability that must not exist in the requested network.
|
||||
* <p>
|
||||
* If the capability was previously added to the list of required capabilities (for
|
||||
* example, it was there by default or added using {@link #addCapability(int)} method), then
|
||||
* it will be removed from the list of required capabilities as well.
|
||||
*
|
||||
* @see #addCapability(int)
|
||||
*
|
||||
* @param capability The capability to add to unwanted capability list.
|
||||
* @return The builder to facilitate chaining.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
|
||||
mNetworkCapabilities.addUnwantedCapability(capability);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely clears all the {@code NetworkCapabilities} from this builder instance,
|
||||
* removing even the capabilities that are set by default when the object is constructed.
|
||||
*
|
||||
* @return The builder to facilitate chaining.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder clearCapabilities() {
|
||||
mNetworkCapabilities.clearAll();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given transport requirement to this builder. These represent
|
||||
* the set of allowed transports for the request. Only networks using one
|
||||
* of these transports will satisfy the request. If no particular transports
|
||||
* are required, none should be specified here.
|
||||
*
|
||||
* @param transportType The transport type to add.
|
||||
* @return The builder to facilitate chaining.
|
||||
*/
|
||||
public Builder addTransportType(@NetworkCapabilities.Transport int transportType) {
|
||||
mNetworkCapabilities.addTransportType(transportType);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes (if found) the given transport from this builder instance.
|
||||
*
|
||||
* @param transportType The transport type to remove.
|
||||
* @return The builder to facilitate chaining.
|
||||
*/
|
||||
public Builder removeTransportType(@NetworkCapabilities.Transport int transportType) {
|
||||
mNetworkCapabilities.removeTransportType(transportType);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public Builder setLinkUpstreamBandwidthKbps(int upKbps) {
|
||||
mNetworkCapabilities.setLinkUpstreamBandwidthKbps(upKbps);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public Builder setLinkDownstreamBandwidthKbps(int downKbps) {
|
||||
mNetworkCapabilities.setLinkDownstreamBandwidthKbps(downKbps);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional bearer specific network specifier.
|
||||
* This has no meaning if a single transport is also not specified, so calling
|
||||
* this without a single transport set will generate an exception, as will
|
||||
* subsequently adding or removing transports after this is set.
|
||||
* </p>
|
||||
* If the {@code networkSpecifier} is provided, it shall be interpreted as follows:
|
||||
* <ul>
|
||||
* <li>If the specifier can be parsed as an integer, it will be treated as a
|
||||
* {@link android.net TelephonyNetworkSpecifier}, and the provided integer will be
|
||||
* interpreted as a SubscriptionId.
|
||||
* <li>If the value is an ethernet interface name, it will be treated as such.
|
||||
* <li>For all other cases, the behavior is undefined.
|
||||
* </ul>
|
||||
*
|
||||
* @param networkSpecifier A {@code String} of either a SubscriptionId in cellular
|
||||
* network request or an ethernet interface name in ethernet
|
||||
* network request.
|
||||
*
|
||||
* @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder setNetworkSpecifier(String networkSpecifier) {
|
||||
try {
|
||||
int subId = Integer.parseInt(networkSpecifier);
|
||||
return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
|
||||
.setSubscriptionId(subId).build());
|
||||
} catch (NumberFormatException nfe) {
|
||||
// A StringNetworkSpecifier does not accept null or empty ("") strings. When network
|
||||
// specifiers were strings a null string and an empty string were considered
|
||||
// equivalent. Hence no meaning is attached to a null or empty ("") string.
|
||||
return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null
|
||||
: new StringNetworkSpecifier(networkSpecifier));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional bearer specific network specifier.
|
||||
* This has no meaning if a single transport is also not specified, so calling
|
||||
* this without a single transport set will generate an exception, as will
|
||||
* subsequently adding or removing transports after this is set.
|
||||
* </p>
|
||||
*
|
||||
* @param networkSpecifier A concrete, parcelable framework class that extends
|
||||
* NetworkSpecifier.
|
||||
*/
|
||||
public Builder setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
|
||||
if (networkSpecifier instanceof MatchAllNetworkSpecifier) {
|
||||
throw new IllegalArgumentException("A MatchAllNetworkSpecifier is not permitted");
|
||||
}
|
||||
mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the signal strength. This is a signed integer, with higher values indicating a
|
||||
* stronger signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same
|
||||
* RSSI units reported by WifiManager.
|
||||
* <p>
|
||||
* Note that when used to register a network callback, this specifies the minimum acceptable
|
||||
* signal strength. When received as the state of an existing network it specifies the
|
||||
* current value. A value of {@code SIGNAL_STRENGTH_UNSPECIFIED} means no value when
|
||||
* received and has no effect when requesting a callback.
|
||||
*
|
||||
* <p>This method requires the caller to hold the
|
||||
* {@link android.Manifest.permission#NETWORK_SIGNAL_STRENGTH_WAKEUP} permission
|
||||
*
|
||||
* @param signalStrength the bearer-specific signal strength.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP)
|
||||
public @NonNull Builder setSignalStrength(int signalStrength) {
|
||||
mNetworkCapabilities.setSignalStrength(signalStrength);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// implement the Parcelable interface
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
networkCapabilities.writeToParcel(dest, flags);
|
||||
dest.writeInt(legacyType);
|
||||
dest.writeInt(requestId);
|
||||
dest.writeString(type.name());
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<NetworkRequest> CREATOR =
|
||||
new Creator<NetworkRequest>() {
|
||||
public NetworkRequest createFromParcel(Parcel in) {
|
||||
NetworkCapabilities nc = NetworkCapabilities.CREATOR.createFromParcel(in);
|
||||
int legacyType = in.readInt();
|
||||
int requestId = in.readInt();
|
||||
Type type = Type.valueOf(in.readString()); // IllegalArgumentException if invalid.
|
||||
NetworkRequest result = new NetworkRequest(nc, legacyType, requestId, type);
|
||||
return result;
|
||||
}
|
||||
public NetworkRequest[] newArray(int size) {
|
||||
return new NetworkRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true iff. this NetworkRequest is of type LISTEN.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean isListen() {
|
||||
return type == Type.LISTEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff. the contained NetworkRequest is one that:
|
||||
*
|
||||
* - should be associated with at most one satisfying network
|
||||
* at a time;
|
||||
*
|
||||
* - should cause a network to be kept up, but not necessarily in
|
||||
* the foreground, if it is the best network which can satisfy the
|
||||
* NetworkRequest.
|
||||
*
|
||||
* For full detail of how isRequest() is used for pairing Networks with
|
||||
* NetworkRequests read rematchNetworkAndRequests().
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean isRequest() {
|
||||
return isForegroundRequest() || isBackgroundRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff. the contained NetworkRequest is one that:
|
||||
*
|
||||
* - should be associated with at most one satisfying network
|
||||
* at a time;
|
||||
*
|
||||
* - should cause a network to be kept up and in the foreground if
|
||||
* it is the best network which can satisfy the NetworkRequest.
|
||||
*
|
||||
* For full detail of how isRequest() is used for pairing Networks with
|
||||
* NetworkRequests read rematchNetworkAndRequests().
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean isForegroundRequest() {
|
||||
return type == Type.TRACK_DEFAULT || type == Type.REQUEST;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff. this NetworkRequest is of type BACKGROUND_REQUEST.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean isBackgroundRequest() {
|
||||
return type == Type.BACKGROUND_REQUEST;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Builder#addCapability(int)
|
||||
*/
|
||||
public boolean hasCapability(@NetCapability int capability) {
|
||||
return networkCapabilities.hasCapability(capability);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Builder#addUnwantedCapability(int)
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean hasUnwantedCapability(@NetCapability int capability) {
|
||||
return networkCapabilities.hasUnwantedCapability(capability);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if and only if the capabilities requested in this NetworkRequest are satisfied
|
||||
* by the provided {@link NetworkCapabilities}.
|
||||
*
|
||||
* @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not
|
||||
* satisfy any request.
|
||||
*/
|
||||
public boolean canBeSatisfiedBy(@Nullable NetworkCapabilities nc) {
|
||||
return networkCapabilities.satisfiedByNetworkCapabilities(nc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Builder#addTransportType(int)
|
||||
*/
|
||||
public boolean hasTransport(@Transport int transportType) {
|
||||
return networkCapabilities.hasTransport(transportType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Builder#setNetworkSpecifier(NetworkSpecifier)
|
||||
*/
|
||||
@Nullable
|
||||
public NetworkSpecifier getNetworkSpecifier() {
|
||||
return networkCapabilities.getNetworkSpecifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the uid of the app making the request.
|
||||
*
|
||||
* Note: This could return {@link Process#INVALID_UID} if the {@link NetworkRequest} object was
|
||||
* not obtained from {@link ConnectivityManager}.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public int getRequestorUid() {
|
||||
return networkCapabilities.getRequestorUid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the package name of the app making the request.
|
||||
*
|
||||
* Note: This could return {@code null} if the {@link NetworkRequest} object was not obtained
|
||||
* from {@link ConnectivityManager}.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@Nullable
|
||||
public String getRequestorPackageName() {
|
||||
return networkCapabilities.getRequestorPackageName();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "NetworkRequest [ " + type + " id=" + requestId +
|
||||
(legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
|
||||
", " + networkCapabilities.toString() + " ]";
|
||||
}
|
||||
|
||||
private int typeToProtoEnum(Type t) {
|
||||
switch (t) {
|
||||
case NONE:
|
||||
return NetworkRequestProto.TYPE_NONE;
|
||||
case LISTEN:
|
||||
return NetworkRequestProto.TYPE_LISTEN;
|
||||
case TRACK_DEFAULT:
|
||||
return NetworkRequestProto.TYPE_TRACK_DEFAULT;
|
||||
case REQUEST:
|
||||
return NetworkRequestProto.TYPE_REQUEST;
|
||||
case BACKGROUND_REQUEST:
|
||||
return NetworkRequestProto.TYPE_BACKGROUND_REQUEST;
|
||||
default:
|
||||
return NetworkRequestProto.TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
|
||||
proto.write(NetworkRequestProto.TYPE, typeToProtoEnum(type));
|
||||
proto.write(NetworkRequestProto.REQUEST_ID, requestId);
|
||||
proto.write(NetworkRequestProto.LEGACY_TYPE, legacyType);
|
||||
networkCapabilities.dumpDebug(proto, NetworkRequestProto.NETWORK_CAPABILITIES);
|
||||
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof NetworkRequest == false) return false;
|
||||
NetworkRequest that = (NetworkRequest)obj;
|
||||
return (that.legacyType == this.legacyType &&
|
||||
that.requestId == this.requestId &&
|
||||
that.type == this.type &&
|
||||
Objects.equals(that.networkCapabilities, this.networkCapabilities));
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return Objects.hash(requestId, legacyType, networkCapabilities, type);
|
||||
}
|
||||
}
|
||||
425
framework/src/android/net/NetworkUtils.java
Normal file
425
framework/src/android/net/NetworkUtils.java
Normal file
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
import android.system.ErrnoException;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.net.module.util.Inet4AddressUtils;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.math.BigInteger;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Locale;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Native methods for managing network interfaces.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class NetworkUtils {
|
||||
|
||||
private static final String TAG = "NetworkUtils";
|
||||
|
||||
/**
|
||||
* Attaches a socket filter that drops all of incoming packets.
|
||||
* @param fd the socket's {@link FileDescriptor}.
|
||||
*/
|
||||
public static native void attachDropAllBPFFilter(FileDescriptor fd) throws SocketException;
|
||||
|
||||
/**
|
||||
* Detaches a socket filter.
|
||||
* @param fd the socket's {@link FileDescriptor}.
|
||||
*/
|
||||
public static native void detachBPFFilter(FileDescriptor fd) throws SocketException;
|
||||
|
||||
/**
|
||||
* Binds the current process to the network designated by {@code netId}. All sockets created
|
||||
* in the future (and not explicitly bound via a bound {@link SocketFactory} (see
|
||||
* {@link Network#getSocketFactory}) will be bound to this network. Note that if this
|
||||
* {@code Network} ever disconnects all sockets created in this way will cease to work. This
|
||||
* is by design so an application doesn't accidentally use sockets it thinks are still bound to
|
||||
* a particular {@code Network}. Passing NETID_UNSET clears the binding.
|
||||
*/
|
||||
public native static boolean bindProcessToNetwork(int netId);
|
||||
|
||||
/**
|
||||
* Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if
|
||||
* {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}.
|
||||
*/
|
||||
public native static int getBoundNetworkForProcess();
|
||||
|
||||
/**
|
||||
* Binds host resolutions performed by this process to the network designated by {@code netId}.
|
||||
* {@link #bindProcessToNetwork} takes precedence over this setting. Passing NETID_UNSET clears
|
||||
* the binding.
|
||||
*
|
||||
* @deprecated This is strictly for legacy usage to support startUsingNetworkFeature().
|
||||
*/
|
||||
@Deprecated
|
||||
public native static boolean bindProcessToNetworkForHostResolution(int netId);
|
||||
|
||||
/**
|
||||
* Explicitly binds {@code fd} to the network designated by {@code netId}. This
|
||||
* overrides any binding via {@link #bindProcessToNetwork}.
|
||||
* @return 0 on success or negative errno on failure.
|
||||
*/
|
||||
public static native int bindSocketToNetwork(FileDescriptor fd, int netId);
|
||||
|
||||
/**
|
||||
* Protect {@code fd} from VPN connections. After protecting, data sent through
|
||||
* this socket will go directly to the underlying network, so its traffic will not be
|
||||
* forwarded through the VPN.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public static native boolean protectFromVpn(FileDescriptor fd);
|
||||
|
||||
/**
|
||||
* Protect {@code socketfd} from VPN connections. After protecting, data sent through
|
||||
* this socket will go directly to the underlying network, so its traffic will not be
|
||||
* forwarded through the VPN.
|
||||
*/
|
||||
public native static boolean protectFromVpn(int socketfd);
|
||||
|
||||
/**
|
||||
* Determine if {@code uid} can access network designated by {@code netId}.
|
||||
* @return {@code true} if {@code uid} can access network, {@code false} otherwise.
|
||||
*/
|
||||
public native static boolean queryUserAccess(int uid, int netId);
|
||||
|
||||
/**
|
||||
* DNS resolver series jni method.
|
||||
* Issue the query {@code msg} on the network designated by {@code netId}.
|
||||
* {@code flags} is an additional config to control actual querying behavior.
|
||||
* @return a file descriptor to watch for read events
|
||||
*/
|
||||
public static native FileDescriptor resNetworkSend(
|
||||
int netId, byte[] msg, int msglen, int flags) throws ErrnoException;
|
||||
|
||||
/**
|
||||
* DNS resolver series jni method.
|
||||
* Look up the {@code nsClass} {@code nsType} Resource Record (RR) associated
|
||||
* with Domain Name {@code dname} on the network designated by {@code netId}.
|
||||
* {@code flags} is an additional config to control actual querying behavior.
|
||||
* @return a file descriptor to watch for read events
|
||||
*/
|
||||
public static native FileDescriptor resNetworkQuery(
|
||||
int netId, String dname, int nsClass, int nsType, int flags) throws ErrnoException;
|
||||
|
||||
/**
|
||||
* DNS resolver series jni method.
|
||||
* Read a result for the query associated with the {@code fd}.
|
||||
* @return DnsResponse containing blob answer and rcode
|
||||
*/
|
||||
public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd)
|
||||
throws ErrnoException;
|
||||
|
||||
/**
|
||||
* DNS resolver series jni method.
|
||||
* Attempts to cancel the in-progress query associated with the {@code fd}.
|
||||
*/
|
||||
public static native void resNetworkCancel(FileDescriptor fd);
|
||||
|
||||
/**
|
||||
* DNS resolver series jni method.
|
||||
* Attempts to get network which resolver will use if no network is explicitly selected.
|
||||
*/
|
||||
public static native Network getDnsNetwork() throws ErrnoException;
|
||||
|
||||
/**
|
||||
* Get the tcp repair window associated with the {@code fd}.
|
||||
*
|
||||
* @param fd the tcp socket's {@link FileDescriptor}.
|
||||
* @return a {@link TcpRepairWindow} object indicates tcp window size.
|
||||
*/
|
||||
public static native TcpRepairWindow getTcpRepairWindow(FileDescriptor fd)
|
||||
throws ErrnoException;
|
||||
|
||||
/**
|
||||
* @see Inet4AddressUtils#intToInet4AddressHTL(int)
|
||||
* @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)}
|
||||
* or {@link Inet4AddressUtils#intToInet4AddressHTL(int)}
|
||||
*/
|
||||
@Deprecated
|
||||
@UnsupportedAppUsage
|
||||
public static InetAddress intToInetAddress(int hostAddress) {
|
||||
return Inet4AddressUtils.intToInet4AddressHTL(hostAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)
|
||||
* @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)}
|
||||
* or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static int inetAddressToInt(Inet4Address inetAddr)
|
||||
throws IllegalArgumentException {
|
||||
return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)
|
||||
* @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)}
|
||||
* or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)}
|
||||
*/
|
||||
@Deprecated
|
||||
@UnsupportedAppUsage
|
||||
public static int prefixLengthToNetmaskInt(int prefixLength)
|
||||
throws IllegalArgumentException {
|
||||
return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a IPv4 netmask integer to a prefix length
|
||||
* @param netmask as an integer (0xff000000 for a /8 subnet)
|
||||
* @return the network prefix length
|
||||
*/
|
||||
public static int netmaskIntToPrefixLength(int netmask) {
|
||||
return Integer.bitCount(netmask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous.
|
||||
* @param netmask as a {@code Inet4Address}.
|
||||
* @return the network prefix length
|
||||
* @throws IllegalArgumentException the specified netmask was not contiguous.
|
||||
* @hide
|
||||
* @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)}
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
@Deprecated
|
||||
public static int netmaskToPrefixLength(Inet4Address netmask) {
|
||||
// This is only here because some apps seem to be using it (@UnsupportedAppUsage).
|
||||
return Inet4AddressUtils.netmaskToPrefixLength(netmask);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create an InetAddress from a string where the string must be a standard
|
||||
* representation of a V4 or V6 address. Avoids doing a DNS lookup on failure
|
||||
* but it will throw an IllegalArgumentException in that case.
|
||||
* @param addrString
|
||||
* @return the InetAddress
|
||||
* @hide
|
||||
* @deprecated Use {@link InetAddresses#parseNumericAddress(String)}, if possible.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
|
||||
@Deprecated
|
||||
public static InetAddress numericToInetAddress(String addrString)
|
||||
throws IllegalArgumentException {
|
||||
return InetAddress.parseNumericAddress(addrString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Masks a raw IP address byte array with the specified prefix length.
|
||||
*/
|
||||
public static void maskRawAddress(byte[] array, int prefixLength) {
|
||||
if (prefixLength < 0 || prefixLength > array.length * 8) {
|
||||
throw new RuntimeException("IP address with " + array.length +
|
||||
" bytes has invalid prefix length " + prefixLength);
|
||||
}
|
||||
|
||||
int offset = prefixLength / 8;
|
||||
int remainder = prefixLength % 8;
|
||||
byte mask = (byte)(0xFF << (8 - remainder));
|
||||
|
||||
if (offset < array.length) array[offset] = (byte)(array[offset] & mask);
|
||||
|
||||
offset++;
|
||||
|
||||
for (; offset < array.length; offset++) {
|
||||
array[offset] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get InetAddress masked with prefixLength. Will never return null.
|
||||
* @param address the IP address to mask with
|
||||
* @param prefixLength the prefixLength used to mask the IP
|
||||
*/
|
||||
public static InetAddress getNetworkPart(InetAddress address, int prefixLength) {
|
||||
byte[] array = address.getAddress();
|
||||
maskRawAddress(array, prefixLength);
|
||||
|
||||
InetAddress netPart = null;
|
||||
try {
|
||||
netPart = InetAddress.getByAddress(array);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException("getNetworkPart error - " + e.toString());
|
||||
}
|
||||
return netPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public static int getImplicitNetmask(Inet4Address address) {
|
||||
// Only here because it seems to be used by apps
|
||||
return Inet4AddressUtils.getImplicitNetmask(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
|
||||
* @hide
|
||||
*/
|
||||
public static Pair<InetAddress, Integer> parseIpAndMask(String ipAndMaskString) {
|
||||
InetAddress address = null;
|
||||
int prefixLength = -1;
|
||||
try {
|
||||
String[] pieces = ipAndMaskString.split("/", 2);
|
||||
prefixLength = Integer.parseInt(pieces[1]);
|
||||
address = InetAddress.parseNumericAddress(pieces[0]);
|
||||
} catch (NullPointerException e) { // Null string.
|
||||
} catch (ArrayIndexOutOfBoundsException e) { // No prefix length.
|
||||
} catch (NumberFormatException e) { // Non-numeric prefix.
|
||||
} catch (IllegalArgumentException e) { // Invalid IP address.
|
||||
}
|
||||
|
||||
if (address == null || prefixLength == -1) {
|
||||
throw new IllegalArgumentException("Invalid IP address and mask " + ipAndMaskString);
|
||||
}
|
||||
|
||||
return new Pair<InetAddress, Integer>(address, prefixLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a 32 char hex string into a Inet6Address.
|
||||
* throws a runtime exception if the string isn't 32 chars, isn't hex or can't be
|
||||
* made into an Inet6Address
|
||||
* @param addrHexString a 32 character hex string representing an IPv6 addr
|
||||
* @return addr an InetAddress representation for the string
|
||||
*/
|
||||
public static InetAddress hexToInet6Address(String addrHexString)
|
||||
throws IllegalArgumentException {
|
||||
try {
|
||||
return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s",
|
||||
addrHexString.substring(0,4), addrHexString.substring(4,8),
|
||||
addrHexString.substring(8,12), addrHexString.substring(12,16),
|
||||
addrHexString.substring(16,20), addrHexString.substring(20,24),
|
||||
addrHexString.substring(24,28), addrHexString.substring(28,32)));
|
||||
} catch (Exception e) {
|
||||
Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e);
|
||||
throw new IllegalArgumentException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim leading zeros from IPv4 address strings
|
||||
* Our base libraries will interpret that as octel..
|
||||
* Must leave non v4 addresses and host names alone.
|
||||
* For example, 192.168.000.010 -> 192.168.0.10
|
||||
* TODO - fix base libraries and remove this function
|
||||
* @param addr a string representing an ip addr
|
||||
* @return a string propertly trimmed
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public static String trimV4AddrZeros(String addr) {
|
||||
if (addr == null) return null;
|
||||
String[] octets = addr.split("\\.");
|
||||
if (octets.length != 4) return addr;
|
||||
StringBuilder builder = new StringBuilder(16);
|
||||
String result = null;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
try {
|
||||
if (octets[i].length() > 3) return addr;
|
||||
builder.append(Integer.parseInt(octets[i]));
|
||||
} catch (NumberFormatException e) {
|
||||
return addr;
|
||||
}
|
||||
if (i < 3) builder.append('.');
|
||||
}
|
||||
result = builder.toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prefix set without overlaps.
|
||||
*
|
||||
* This expects the src set to be sorted from shorter to longer. Results are undefined
|
||||
* failing this condition. The returned prefix set is sorted in the same order as the
|
||||
* passed set, with the same comparator.
|
||||
*/
|
||||
private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) {
|
||||
final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator());
|
||||
// Prefixes match addresses that share their upper part up to their length, therefore
|
||||
// the only kind of possible overlap in two prefixes is strict inclusion of the longer
|
||||
// (more restrictive) in the shorter (including equivalence if they have the same
|
||||
// length).
|
||||
// Because prefixes in the src set are sorted from shorter to longer, deduplicating
|
||||
// is done by simply iterating in order, and not adding any longer prefix that is
|
||||
// already covered by a shorter one.
|
||||
newPrefixes:
|
||||
for (IpPrefix newPrefix : src) {
|
||||
for (IpPrefix existingPrefix : dst) {
|
||||
if (existingPrefix.containsPrefix(newPrefix)) {
|
||||
continue newPrefixes;
|
||||
}
|
||||
}
|
||||
dst.add(newPrefix);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how many IPv4 addresses match any of the prefixes in the passed ordered set.
|
||||
*
|
||||
* Obviously this returns an integral value between 0 and 2**32.
|
||||
* The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the
|
||||
* set is not ordered smallest prefix to longer prefix.
|
||||
*
|
||||
* @param prefixes the set of prefixes, ordered by length
|
||||
*/
|
||||
public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) {
|
||||
long routedIPCount = 0;
|
||||
for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
|
||||
if (!prefix.isIPv4()) {
|
||||
Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount");
|
||||
}
|
||||
int rank = 32 - prefix.getPrefixLength();
|
||||
routedIPCount += 1L << rank;
|
||||
}
|
||||
return routedIPCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how many IPv6 addresses match any of the prefixes in the passed ordered set.
|
||||
*
|
||||
* This returns a BigInteger between 0 and 2**128.
|
||||
* The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the
|
||||
* set is not ordered smallest prefix to longer prefix.
|
||||
*/
|
||||
public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) {
|
||||
BigInteger routedIPCount = BigInteger.ZERO;
|
||||
for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
|
||||
if (!prefix.isIPv6()) {
|
||||
Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount");
|
||||
}
|
||||
int rank = 128 - prefix.getPrefixLength();
|
||||
routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank));
|
||||
}
|
||||
return routedIPCount;
|
||||
}
|
||||
|
||||
}
|
||||
138
framework/src/android/net/PacProxySelector.java
Normal file
138
framework/src/android/net/PacProxySelector.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.net.IProxyService;
|
||||
|
||||
import com.google.android.collect.Lists;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.Proxy;
|
||||
import java.net.Proxy.Type;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class PacProxySelector extends ProxySelector {
|
||||
private static final String TAG = "PacProxySelector";
|
||||
public static final String PROXY_SERVICE = "com.android.net.IProxyService";
|
||||
private static final String SOCKS = "SOCKS ";
|
||||
private static final String PROXY = "PROXY ";
|
||||
|
||||
private IProxyService mProxyService;
|
||||
private final List<Proxy> mDefaultList;
|
||||
|
||||
public PacProxySelector() {
|
||||
mProxyService = IProxyService.Stub.asInterface(
|
||||
ServiceManager.getService(PROXY_SERVICE));
|
||||
if (mProxyService == null) {
|
||||
// Added because of b10267814 where mako is restarting.
|
||||
Log.e(TAG, "PacProxyInstaller: no proxy service");
|
||||
}
|
||||
mDefaultList = Lists.newArrayList(java.net.Proxy.NO_PROXY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Proxy> select(URI uri) {
|
||||
if (mProxyService == null) {
|
||||
mProxyService = IProxyService.Stub.asInterface(
|
||||
ServiceManager.getService(PROXY_SERVICE));
|
||||
}
|
||||
if (mProxyService == null) {
|
||||
Log.e(TAG, "select: no proxy service return NO_PROXY");
|
||||
return Lists.newArrayList(java.net.Proxy.NO_PROXY);
|
||||
}
|
||||
String response = null;
|
||||
String urlString;
|
||||
try {
|
||||
// Strip path and username/password from URI so it's not visible to PAC script. The
|
||||
// path often contains credentials the app does not want exposed to a potentially
|
||||
// malicious PAC script.
|
||||
if (!"http".equalsIgnoreCase(uri.getScheme())) {
|
||||
uri = new URI(uri.getScheme(), null, uri.getHost(), uri.getPort(), "/", null, null);
|
||||
}
|
||||
urlString = uri.toURL().toString();
|
||||
} catch (URISyntaxException e) {
|
||||
urlString = uri.getHost();
|
||||
} catch (MalformedURLException e) {
|
||||
urlString = uri.getHost();
|
||||
}
|
||||
try {
|
||||
response = mProxyService.resolvePacFile(uri.getHost(), urlString);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error resolving PAC File", e);
|
||||
}
|
||||
if (response == null) {
|
||||
return mDefaultList;
|
||||
}
|
||||
|
||||
return parseResponse(response);
|
||||
}
|
||||
|
||||
private static List<Proxy> parseResponse(String response) {
|
||||
String[] split = response.split(";");
|
||||
List<Proxy> ret = Lists.newArrayList();
|
||||
for (String s : split) {
|
||||
String trimmed = s.trim();
|
||||
if (trimmed.equals("DIRECT")) {
|
||||
ret.add(java.net.Proxy.NO_PROXY);
|
||||
} else if (trimmed.startsWith(PROXY)) {
|
||||
Proxy proxy = proxyFromHostPort(Type.HTTP, trimmed.substring(PROXY.length()));
|
||||
if (proxy != null) {
|
||||
ret.add(proxy);
|
||||
}
|
||||
} else if (trimmed.startsWith(SOCKS)) {
|
||||
Proxy proxy = proxyFromHostPort(Type.SOCKS, trimmed.substring(SOCKS.length()));
|
||||
if (proxy != null) {
|
||||
ret.add(proxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret.size() == 0) {
|
||||
ret.add(java.net.Proxy.NO_PROXY);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static Proxy proxyFromHostPort(Proxy.Type type, String hostPortString) {
|
||||
try {
|
||||
String[] hostPort = hostPortString.split(":");
|
||||
String host = hostPort[0];
|
||||
int port = Integer.parseInt(hostPort[1]);
|
||||
return new Proxy(type, InetSocketAddress.createUnresolved(host, port));
|
||||
} catch (NumberFormatException|ArrayIndexOutOfBoundsException e) {
|
||||
Log.d(TAG, "Unable to parse proxy " + hostPortString + " " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectFailed(URI uri, SocketAddress address, IOException failure) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
294
framework/src/android/net/Proxy.java
Normal file
294
framework/src/android/net/Proxy.java
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.net.module.util.ProxyUtils;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A convenience class for accessing the user and default proxy
|
||||
* settings.
|
||||
*/
|
||||
public final class Proxy {
|
||||
|
||||
private static final String TAG = "Proxy";
|
||||
|
||||
private static final ProxySelector sDefaultProxySelector;
|
||||
|
||||
/**
|
||||
* Used to notify an app that's caching the proxy that either the default
|
||||
* connection has changed or any connection's proxy has changed. The new
|
||||
* proxy should be queried using {@link ConnectivityManager#getDefaultProxy()}.
|
||||
*
|
||||
* <p class="note">This is a protected intent that can only be sent by the system
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE";
|
||||
/**
|
||||
* Intent extra included with {@link #PROXY_CHANGE_ACTION} intents.
|
||||
* It describes the new proxy being used (as a {@link ProxyInfo} object).
|
||||
* @deprecated Because {@code PROXY_CHANGE_ACTION} is sent whenever the proxy
|
||||
* for any network on the system changes, applications should always use
|
||||
* {@link ConnectivityManager#getDefaultProxy()} or
|
||||
* {@link ConnectivityManager#getLinkProperties(Network)}.{@link LinkProperties#getHttpProxy()}
|
||||
* to get the proxy for the Network(s) they are using.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
|
||||
|
||||
/** @hide */
|
||||
public static final int PROXY_VALID = 0;
|
||||
/** @hide */
|
||||
public static final int PROXY_HOSTNAME_EMPTY = 1;
|
||||
/** @hide */
|
||||
public static final int PROXY_HOSTNAME_INVALID = 2;
|
||||
/** @hide */
|
||||
public static final int PROXY_PORT_EMPTY = 3;
|
||||
/** @hide */
|
||||
public static final int PROXY_PORT_INVALID = 4;
|
||||
/** @hide */
|
||||
public static final int PROXY_EXCLLIST_INVALID = 5;
|
||||
|
||||
private static ConnectivityManager sConnectivityManager = null;
|
||||
|
||||
// Hostname / IP REGEX validation
|
||||
// Matches blank input, ips, and domain names
|
||||
private static final String NAME_IP_REGEX =
|
||||
"[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*";
|
||||
|
||||
private static final String HOSTNAME_REGEXP = "^$|^" + NAME_IP_REGEX + "$";
|
||||
|
||||
private static final Pattern HOSTNAME_PATTERN;
|
||||
|
||||
private static final String EXCL_REGEX =
|
||||
"[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*(\\.[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*)*";
|
||||
|
||||
private static final String EXCLLIST_REGEXP = "^$|^" + EXCL_REGEX + "(," + EXCL_REGEX + ")*$";
|
||||
|
||||
private static final Pattern EXCLLIST_PATTERN;
|
||||
|
||||
static {
|
||||
HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
|
||||
EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP);
|
||||
sDefaultProxySelector = ProxySelector.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the proxy object to be used for the URL given as parameter.
|
||||
* @param ctx A Context used to get the settings for the proxy host.
|
||||
* @param url A URL to be accessed. Used to evaluate exclusion list.
|
||||
* @return Proxy (java.net) object containing the host name. If the
|
||||
* user did not set a hostname it returns the default host.
|
||||
* A null value means that no host is to be used.
|
||||
* {@hide}
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public static final java.net.Proxy getProxy(Context ctx, String url) {
|
||||
String host = "";
|
||||
if ((url != null) && !isLocalHost(host)) {
|
||||
URI uri = URI.create(url);
|
||||
ProxySelector proxySelector = ProxySelector.getDefault();
|
||||
|
||||
List<java.net.Proxy> proxyList = proxySelector.select(uri);
|
||||
|
||||
if (proxyList.size() > 0) {
|
||||
return proxyList.get(0);
|
||||
}
|
||||
}
|
||||
return java.net.Proxy.NO_PROXY;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the proxy host set by the user.
|
||||
* @param ctx A Context used to get the settings for the proxy host.
|
||||
* @return String containing the host name. If the user did not set a host
|
||||
* name it returns the default host. A null value means that no
|
||||
* host is to be used.
|
||||
* @deprecated Use standard java vm proxy values to find the host, port
|
||||
* and exclusion list. This call ignores the exclusion list.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String getHost(Context ctx) {
|
||||
java.net.Proxy proxy = getProxy(ctx, null);
|
||||
if (proxy == java.net.Proxy.NO_PROXY) return null;
|
||||
try {
|
||||
return ((InetSocketAddress)(proxy.address())).getHostName();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the proxy port set by the user.
|
||||
* @param ctx A Context used to get the settings for the proxy port.
|
||||
* @return The port number to use or -1 if no proxy is to be used.
|
||||
* @deprecated Use standard java vm proxy values to find the host, port
|
||||
* and exclusion list. This call ignores the exclusion list.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int getPort(Context ctx) {
|
||||
java.net.Proxy proxy = getProxy(ctx, null);
|
||||
if (proxy == java.net.Proxy.NO_PROXY) return -1;
|
||||
try {
|
||||
return ((InetSocketAddress)(proxy.address())).getPort();
|
||||
} catch (Exception e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default proxy host specified by the carrier.
|
||||
* @return String containing the host name or null if there is no proxy for
|
||||
* this carrier.
|
||||
* @deprecated Use standard java vm proxy values to find the host, port and
|
||||
* exclusion list. This call ignores the exclusion list and no
|
||||
* longer reports only mobile-data apn-based proxy values.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String getDefaultHost() {
|
||||
String host = System.getProperty("http.proxyHost");
|
||||
if (TextUtils.isEmpty(host)) return null;
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default proxy port specified by the carrier.
|
||||
* @return The port number to be used with the proxy host or -1 if there is
|
||||
* no proxy for this carrier.
|
||||
* @deprecated Use standard java vm proxy values to find the host, port and
|
||||
* exclusion list. This call ignores the exclusion list and no
|
||||
* longer reports only mobile-data apn-based proxy values.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int getDefaultPort() {
|
||||
if (getDefaultHost() == null) return -1;
|
||||
try {
|
||||
return Integer.parseInt(System.getProperty("http.proxyPort"));
|
||||
} catch (NumberFormatException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean isLocalHost(String host) {
|
||||
if (host == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (host != null) {
|
||||
if (host.equalsIgnoreCase("localhost")) {
|
||||
return true;
|
||||
}
|
||||
if (InetAddresses.parseNumericAddress(host).isLoopbackAddress()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException iex) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate syntax of hostname, port and exclusion list entries
|
||||
* {@hide}
|
||||
*/
|
||||
public static int validate(String hostname, String port, String exclList) {
|
||||
Matcher match = HOSTNAME_PATTERN.matcher(hostname);
|
||||
Matcher listMatch = EXCLLIST_PATTERN.matcher(exclList);
|
||||
|
||||
if (!match.matches()) return PROXY_HOSTNAME_INVALID;
|
||||
|
||||
if (!listMatch.matches()) return PROXY_EXCLLIST_INVALID;
|
||||
|
||||
if (hostname.length() > 0 && port.length() == 0) return PROXY_PORT_EMPTY;
|
||||
|
||||
if (port.length() > 0) {
|
||||
if (hostname.length() == 0) return PROXY_HOSTNAME_EMPTY;
|
||||
int portVal = -1;
|
||||
try {
|
||||
portVal = Integer.parseInt(port);
|
||||
} catch (NumberFormatException ex) {
|
||||
return PROXY_PORT_INVALID;
|
||||
}
|
||||
if (portVal <= 0 || portVal > 0xFFFF) return PROXY_PORT_INVALID;
|
||||
}
|
||||
return PROXY_VALID;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public static final void setHttpProxySystemProperty(ProxyInfo p) {
|
||||
String host = null;
|
||||
String port = null;
|
||||
String exclList = null;
|
||||
Uri pacFileUrl = Uri.EMPTY;
|
||||
if (p != null) {
|
||||
host = p.getHost();
|
||||
port = Integer.toString(p.getPort());
|
||||
exclList = ProxyUtils.exclusionListAsString(p.getExclusionList());
|
||||
pacFileUrl = p.getPacFileUrl();
|
||||
}
|
||||
setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static final void setHttpProxySystemProperty(String host, String port, String exclList,
|
||||
Uri pacFileUrl) {
|
||||
if (exclList != null) exclList = exclList.replace(",", "|");
|
||||
if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList);
|
||||
if (host != null) {
|
||||
System.setProperty("http.proxyHost", host);
|
||||
System.setProperty("https.proxyHost", host);
|
||||
} else {
|
||||
System.clearProperty("http.proxyHost");
|
||||
System.clearProperty("https.proxyHost");
|
||||
}
|
||||
if (port != null) {
|
||||
System.setProperty("http.proxyPort", port);
|
||||
System.setProperty("https.proxyPort", port);
|
||||
} else {
|
||||
System.clearProperty("http.proxyPort");
|
||||
System.clearProperty("https.proxyPort");
|
||||
}
|
||||
if (exclList != null) {
|
||||
System.setProperty("http.nonProxyHosts", exclList);
|
||||
System.setProperty("https.nonProxyHosts", exclList);
|
||||
} else {
|
||||
System.clearProperty("http.nonProxyHosts");
|
||||
System.clearProperty("https.nonProxyHosts");
|
||||
}
|
||||
if (!Uri.EMPTY.equals(pacFileUrl)) {
|
||||
ProxySelector.setDefault(new PacProxySelector());
|
||||
} else {
|
||||
ProxySelector.setDefault(sDefaultProxySelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
framework/src/android/net/ProxyInfo.aidl
Normal file
21
framework/src/android/net/ProxyInfo.aidl
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2010 The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable ProxyInfo;
|
||||
|
||||
367
framework/src/android/net/ProxyInfo.java
Normal file
367
framework/src/android/net/ProxyInfo.java
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URLConnection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Describes a proxy configuration.
|
||||
*
|
||||
* Proxy configurations are already integrated within the {@code java.net} and
|
||||
* Apache HTTP stack. So {@link URLConnection} and Apache's {@code HttpClient} will use
|
||||
* them automatically.
|
||||
*
|
||||
* Other HTTP stacks will need to obtain the proxy info from
|
||||
* {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}.
|
||||
*/
|
||||
public class ProxyInfo implements Parcelable {
|
||||
|
||||
private final String mHost;
|
||||
private final int mPort;
|
||||
private final String mExclusionList;
|
||||
private final String[] mParsedExclusionList;
|
||||
private final Uri mPacFileUrl;
|
||||
|
||||
/**
|
||||
*@hide
|
||||
*/
|
||||
public static final String LOCAL_EXCL_LIST = "";
|
||||
/**
|
||||
*@hide
|
||||
*/
|
||||
public static final int LOCAL_PORT = -1;
|
||||
/**
|
||||
*@hide
|
||||
*/
|
||||
public static final String LOCAL_HOST = "localhost";
|
||||
|
||||
/**
|
||||
* Constructs a {@link ProxyInfo} object that points at a Direct proxy
|
||||
* on the specified host and port.
|
||||
*/
|
||||
public static ProxyInfo buildDirectProxy(String host, int port) {
|
||||
return new ProxyInfo(host, port, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@link ProxyInfo} object that points at a Direct proxy
|
||||
* on the specified host and port.
|
||||
*
|
||||
* The proxy will not be used to access any host in exclusion list, exclList.
|
||||
*
|
||||
* @param exclList Hosts to exclude using the proxy on connections for. These
|
||||
* hosts can use wildcards such as *.example.com.
|
||||
*/
|
||||
public static ProxyInfo buildDirectProxy(String host, int port, List<String> exclList) {
|
||||
String[] array = exclList.toArray(new String[exclList.size()]);
|
||||
return new ProxyInfo(host, port, TextUtils.join(",", array), array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link ProxyInfo} that will download and run the PAC script
|
||||
* at the specified URL.
|
||||
*/
|
||||
public static ProxyInfo buildPacProxy(Uri pacUri) {
|
||||
return new ProxyInfo(pacUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link ProxyInfo} object that will download and run the PAC script at the
|
||||
* specified URL and port.
|
||||
*/
|
||||
@NonNull
|
||||
public static ProxyInfo buildPacProxy(@NonNull Uri pacUrl, int port) {
|
||||
return new ProxyInfo(pacUrl, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ProxyProperties that points at a HTTP Proxy.
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public ProxyInfo(String host, int port, String exclList) {
|
||||
mHost = host;
|
||||
mPort = port;
|
||||
mExclusionList = exclList;
|
||||
mParsedExclusionList = parseExclusionList(mExclusionList);
|
||||
mPacFileUrl = Uri.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ProxyProperties that points at a PAC URL.
|
||||
* @hide
|
||||
*/
|
||||
public ProxyInfo(@NonNull Uri pacFileUrl) {
|
||||
mHost = LOCAL_HOST;
|
||||
mPort = LOCAL_PORT;
|
||||
mExclusionList = LOCAL_EXCL_LIST;
|
||||
mParsedExclusionList = parseExclusionList(mExclusionList);
|
||||
if (pacFileUrl == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
mPacFileUrl = pacFileUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only used in PacProxyInstaller after Local Proxy is bound.
|
||||
* @hide
|
||||
*/
|
||||
public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) {
|
||||
mHost = LOCAL_HOST;
|
||||
mPort = localProxyPort;
|
||||
mExclusionList = LOCAL_EXCL_LIST;
|
||||
mParsedExclusionList = parseExclusionList(mExclusionList);
|
||||
if (pacFileUrl == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
mPacFileUrl = pacFileUrl;
|
||||
}
|
||||
|
||||
private static String[] parseExclusionList(String exclusionList) {
|
||||
if (exclusionList == null) {
|
||||
return new String[0];
|
||||
} else {
|
||||
return exclusionList.toLowerCase(Locale.ROOT).split(",");
|
||||
}
|
||||
}
|
||||
|
||||
private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) {
|
||||
mHost = host;
|
||||
mPort = port;
|
||||
mExclusionList = exclList;
|
||||
mParsedExclusionList = parsedExclList;
|
||||
mPacFileUrl = Uri.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* A copy constructor to hold proxy properties.
|
||||
*/
|
||||
public ProxyInfo(@Nullable ProxyInfo source) {
|
||||
if (source != null) {
|
||||
mHost = source.getHost();
|
||||
mPort = source.getPort();
|
||||
mPacFileUrl = source.mPacFileUrl;
|
||||
mExclusionList = source.getExclusionListAsString();
|
||||
mParsedExclusionList = source.mParsedExclusionList;
|
||||
} else {
|
||||
mHost = null;
|
||||
mPort = 0;
|
||||
mExclusionList = null;
|
||||
mParsedExclusionList = null;
|
||||
mPacFileUrl = Uri.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public InetSocketAddress getSocketAddress() {
|
||||
InetSocketAddress inetSocketAddress = null;
|
||||
try {
|
||||
inetSocketAddress = new InetSocketAddress(mHost, mPort);
|
||||
} catch (IllegalArgumentException e) { }
|
||||
return inetSocketAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL of the current PAC script or null if there is
|
||||
* no PAC script.
|
||||
*/
|
||||
public Uri getPacFileUrl() {
|
||||
return mPacFileUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* When configured to use a Direct Proxy this returns the host
|
||||
* of the proxy.
|
||||
*/
|
||||
public String getHost() {
|
||||
return mHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* When configured to use a Direct Proxy this returns the port
|
||||
* of the proxy
|
||||
*/
|
||||
public int getPort() {
|
||||
return mPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* When configured to use a Direct Proxy this returns the list
|
||||
* of hosts for which the proxy is ignored.
|
||||
*/
|
||||
public String[] getExclusionList() {
|
||||
return mParsedExclusionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* comma separated
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public String getExclusionListAsString() {
|
||||
return mExclusionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the pattern of proxy is valid, otherwise return false.
|
||||
*/
|
||||
public boolean isValid() {
|
||||
if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
|
||||
return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
|
||||
mPort == 0 ? "" : Integer.toString(mPort),
|
||||
mExclusionList == null ? "" : mExclusionList);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public java.net.Proxy makeProxy() {
|
||||
java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
|
||||
if (mHost != null) {
|
||||
try {
|
||||
InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort);
|
||||
proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress);
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (!Uri.EMPTY.equals(mPacFileUrl)) {
|
||||
sb.append("PAC Script: ");
|
||||
sb.append(mPacFileUrl);
|
||||
}
|
||||
if (mHost != null) {
|
||||
sb.append("[");
|
||||
sb.append(mHost);
|
||||
sb.append("] ");
|
||||
sb.append(Integer.toString(mPort));
|
||||
if (mExclusionList != null) {
|
||||
sb.append(" xl=").append(mExclusionList);
|
||||
}
|
||||
} else {
|
||||
sb.append("[ProxyProperties.mHost == null]");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof ProxyInfo)) return false;
|
||||
ProxyInfo p = (ProxyInfo)o;
|
||||
// If PAC URL is present in either then they must be equal.
|
||||
// Other parameters will only be for fall back.
|
||||
if (!Uri.EMPTY.equals(mPacFileUrl)) {
|
||||
return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
|
||||
}
|
||||
if (!Uri.EMPTY.equals(p.mPacFileUrl)) {
|
||||
return false;
|
||||
}
|
||||
if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) {
|
||||
return false;
|
||||
}
|
||||
if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
|
||||
return false;
|
||||
}
|
||||
if (mHost != null && p.mHost == null) return false;
|
||||
if (mHost == null && p.mHost != null) return false;
|
||||
if (mPort != p.mPort) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface
|
||||
* @hide
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
/*
|
||||
* generate hashcode based on significant fields
|
||||
*/
|
||||
public int hashCode() {
|
||||
return ((null == mHost) ? 0 : mHost.hashCode())
|
||||
+ ((null == mExclusionList) ? 0 : mExclusionList.hashCode())
|
||||
+ mPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface.
|
||||
* @hide
|
||||
*/
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
if (!Uri.EMPTY.equals(mPacFileUrl)) {
|
||||
dest.writeByte((byte)1);
|
||||
mPacFileUrl.writeToParcel(dest, 0);
|
||||
dest.writeInt(mPort);
|
||||
return;
|
||||
} else {
|
||||
dest.writeByte((byte)0);
|
||||
}
|
||||
if (mHost != null) {
|
||||
dest.writeByte((byte)1);
|
||||
dest.writeString(mHost);
|
||||
dest.writeInt(mPort);
|
||||
} else {
|
||||
dest.writeByte((byte)0);
|
||||
}
|
||||
dest.writeString(mExclusionList);
|
||||
dest.writeStringArray(mParsedExclusionList);
|
||||
}
|
||||
|
||||
public static final @android.annotation.NonNull Creator<ProxyInfo> CREATOR =
|
||||
new Creator<ProxyInfo>() {
|
||||
public ProxyInfo createFromParcel(Parcel in) {
|
||||
String host = null;
|
||||
int port = 0;
|
||||
if (in.readByte() != 0) {
|
||||
Uri url = Uri.CREATOR.createFromParcel(in);
|
||||
int localPort = in.readInt();
|
||||
return new ProxyInfo(url, localPort);
|
||||
}
|
||||
if (in.readByte() != 0) {
|
||||
host = in.readString();
|
||||
port = in.readInt();
|
||||
}
|
||||
String exclList = in.readString();
|
||||
String[] parsedExclList = in.createStringArray();
|
||||
ProxyInfo proxyProperties = new ProxyInfo(host, port, exclList, parsedExclList);
|
||||
return proxyProperties;
|
||||
}
|
||||
|
||||
public ProxyInfo[] newArray(int size) {
|
||||
return new ProxyInfo[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
19
framework/src/android/net/RouteInfo.aidl
Normal file
19
framework/src/android/net/RouteInfo.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable RouteInfo;
|
||||
658
framework/src/android/net/RouteInfo.java
Normal file
658
framework/src/android/net/RouteInfo.java
Normal file
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.net.module.util.NetUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a network route.
|
||||
* <p>
|
||||
* This is used both to describe static network configuration and live network
|
||||
* configuration information.
|
||||
*
|
||||
* A route contains three pieces of information:
|
||||
* <ul>
|
||||
* <li>a destination {@link IpPrefix} specifying the network destinations covered by this route.
|
||||
* If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6)
|
||||
* implied by the gateway IP address.
|
||||
* <li>a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it
|
||||
* indicates a directly-connected route.
|
||||
* <li>an interface (which may be unspecified).
|
||||
* </ul>
|
||||
* Either the destination or the gateway may be {@code null}, but not both. If the
|
||||
* destination and gateway are both specified, they must be of the same address family
|
||||
* (IPv4 or IPv6).
|
||||
*/
|
||||
public final class RouteInfo implements Parcelable {
|
||||
/** @hide */
|
||||
@IntDef(value = {
|
||||
RTN_UNICAST,
|
||||
RTN_UNREACHABLE,
|
||||
RTN_THROW,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface RouteType {}
|
||||
|
||||
/**
|
||||
* The IP destination address for this route.
|
||||
*/
|
||||
@NonNull
|
||||
private final IpPrefix mDestination;
|
||||
|
||||
/**
|
||||
* The gateway address for this route.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
@Nullable
|
||||
private final InetAddress mGateway;
|
||||
|
||||
/**
|
||||
* The interface for this route.
|
||||
*/
|
||||
@Nullable
|
||||
private final String mInterface;
|
||||
|
||||
|
||||
/** Unicast route. @hide */
|
||||
@SystemApi
|
||||
public static final int RTN_UNICAST = 1;
|
||||
|
||||
/** Unreachable route. @hide */
|
||||
@SystemApi
|
||||
public static final int RTN_UNREACHABLE = 7;
|
||||
|
||||
/** Throw route. @hide */
|
||||
@SystemApi
|
||||
public static final int RTN_THROW = 9;
|
||||
|
||||
/**
|
||||
* The type of this route; one of the RTN_xxx constants above.
|
||||
*/
|
||||
private final int mType;
|
||||
|
||||
/**
|
||||
* The maximum transmission unit size for this route.
|
||||
*/
|
||||
private final int mMtu;
|
||||
|
||||
// Derived data members.
|
||||
// TODO: remove these.
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||
private final boolean mIsHost;
|
||||
private final boolean mHasGateway;
|
||||
|
||||
/**
|
||||
* Constructs a RouteInfo object.
|
||||
*
|
||||
* If destination is null, then gateway must be specified and the
|
||||
* constructed route is either the IPv4 default route <code>0.0.0.0</code>
|
||||
* if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
|
||||
* route <code>::/0</code> if gateway is an instance of
|
||||
* {@link Inet6Address}.
|
||||
* <p>
|
||||
* destination and gateway may not both be null.
|
||||
*
|
||||
* @param destination the destination prefix
|
||||
* @param gateway the IP address to route packets through
|
||||
* @param iface the interface name to send packets on
|
||||
* @param type the type of this route
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
|
||||
@Nullable String iface, @RouteType int type) {
|
||||
this(destination, gateway, iface, type, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a RouteInfo object.
|
||||
*
|
||||
* If destination is null, then gateway must be specified and the
|
||||
* constructed route is either the IPv4 default route <code>0.0.0.0</code>
|
||||
* if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
|
||||
* route <code>::/0</code> if gateway is an instance of
|
||||
* {@link Inet6Address}.
|
||||
* <p>
|
||||
* destination and gateway may not both be null.
|
||||
*
|
||||
* @param destination the destination prefix
|
||||
* @param gateway the IP address to route packets through
|
||||
* @param iface the interface name to send packets on
|
||||
* @param type the type of this route
|
||||
* @param mtu the maximum transmission unit size for this route
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
|
||||
@Nullable String iface, @RouteType int type, int mtu) {
|
||||
switch (type) {
|
||||
case RTN_UNICAST:
|
||||
case RTN_UNREACHABLE:
|
||||
case RTN_THROW:
|
||||
// TODO: It would be nice to ensure that route types that don't have nexthops or
|
||||
// interfaces, such as unreachable or throw, can't be created if an interface or
|
||||
// a gateway is specified. This is a bit too complicated to do at the moment
|
||||
// because:
|
||||
//
|
||||
// - LinkProperties sets the interface on routes added to it, and modifies the
|
||||
// interfaces of all the routes when its interface name changes.
|
||||
// - Even when the gateway is null, we store a non-null gateway here.
|
||||
//
|
||||
// For now, we just rely on the code that sets routes to do things properly.
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown route type " + type);
|
||||
}
|
||||
|
||||
if (destination == null) {
|
||||
if (gateway != null) {
|
||||
if (gateway instanceof Inet4Address) {
|
||||
destination = new IpPrefix(Inet4Address.ANY, 0);
|
||||
} else {
|
||||
destination = new IpPrefix(Inet6Address.ANY, 0);
|
||||
}
|
||||
} else {
|
||||
// no destination, no gateway. invalid.
|
||||
throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," +
|
||||
destination);
|
||||
}
|
||||
}
|
||||
// TODO: set mGateway to null if there is no gateway. This is more correct, saves space, and
|
||||
// matches the documented behaviour. Before we can do this we need to fix all callers (e.g.,
|
||||
// ConnectivityService) to stop doing things like r.getGateway().equals(), ... .
|
||||
if (gateway == null) {
|
||||
if (destination.getAddress() instanceof Inet4Address) {
|
||||
gateway = Inet4Address.ANY;
|
||||
} else {
|
||||
gateway = Inet6Address.ANY;
|
||||
}
|
||||
}
|
||||
mHasGateway = (!gateway.isAnyLocalAddress());
|
||||
|
||||
if ((destination.getAddress() instanceof Inet4Address
|
||||
&& !(gateway instanceof Inet4Address))
|
||||
|| (destination.getAddress() instanceof Inet6Address
|
||||
&& !(gateway instanceof Inet6Address))) {
|
||||
throw new IllegalArgumentException("address family mismatch in RouteInfo constructor");
|
||||
}
|
||||
mDestination = destination; // IpPrefix objects are immutable.
|
||||
mGateway = gateway; // InetAddress objects are immutable.
|
||||
mInterface = iface; // Strings are immutable.
|
||||
mType = type;
|
||||
mIsHost = isHost();
|
||||
mMtu = mtu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code RouteInfo} object.
|
||||
*
|
||||
* If destination is null, then gateway must be specified and the
|
||||
* constructed route is either the IPv4 default route <code>0.0.0.0</code>
|
||||
* if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
|
||||
* route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
|
||||
* <p>
|
||||
* Destination and gateway may not both be null.
|
||||
*
|
||||
* @param destination the destination address and prefix in an {@link IpPrefix}
|
||||
* @param gateway the {@link InetAddress} to route packets through
|
||||
* @param iface the interface name to send packets on
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
|
||||
@Nullable String iface) {
|
||||
this(destination, gateway, iface, RTN_UNICAST);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway,
|
||||
@Nullable String iface) {
|
||||
this(destination == null ? null :
|
||||
new IpPrefix(destination.getAddress(), destination.getPrefixLength()),
|
||||
gateway, iface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code RouteInfo} object.
|
||||
*
|
||||
* If destination is null, then gateway must be specified and the
|
||||
* constructed route is either the IPv4 default route <code>0.0.0.0</code>
|
||||
* if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
|
||||
* route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
|
||||
* <p>
|
||||
* Destination and gateway may not both be null.
|
||||
*
|
||||
* @param destination the destination address and prefix in an {@link IpPrefix}
|
||||
* @param gateway the {@link InetAddress} to route packets through
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) {
|
||||
this(destination, gateway, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*
|
||||
* TODO: Remove this.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) {
|
||||
this(destination, gateway, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a default {@code RouteInfo} object.
|
||||
*
|
||||
* @param gateway the {@link InetAddress} to route packets through
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public RouteInfo(@NonNull InetAddress gateway) {
|
||||
this((IpPrefix) null, gateway, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a {@code RouteInfo} object representing a direct connected subnet.
|
||||
*
|
||||
* @param destination the {@link IpPrefix} describing the address and prefix
|
||||
* length of the subnet.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public RouteInfo(@NonNull IpPrefix destination) {
|
||||
this(destination, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public RouteInfo(@NonNull LinkAddress destination) {
|
||||
this(destination, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) {
|
||||
this(destination, null, null, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) {
|
||||
return makeHostRoute(host, null, iface);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway,
|
||||
@Nullable String iface) {
|
||||
if (host == null) return null;
|
||||
|
||||
if (host instanceof Inet4Address) {
|
||||
return new RouteInfo(new IpPrefix(host, 32), gateway, iface);
|
||||
} else {
|
||||
return new RouteInfo(new IpPrefix(host, 128), gateway, iface);
|
||||
}
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
|
||||
private boolean isHost() {
|
||||
return (mDestination.getAddress() instanceof Inet4Address &&
|
||||
mDestination.getPrefixLength() == 32) ||
|
||||
(mDestination.getAddress() instanceof Inet6Address &&
|
||||
mDestination.getPrefixLength() == 128);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the destination address and prefix length in the form of an {@link IpPrefix}.
|
||||
*
|
||||
* @return {@link IpPrefix} specifying the destination. This is never {@code null}.
|
||||
*/
|
||||
@NonNull
|
||||
public IpPrefix getDestination() {
|
||||
return mDestination;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Convert callers to use IpPrefix and then remove.
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public LinkAddress getDestinationLinkAddress() {
|
||||
return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the gateway or next hop {@link InetAddress} for this route.
|
||||
*
|
||||
* @return {@link InetAddress} specifying the gateway or next hop. This may be
|
||||
* {@code null} for a directly-connected route."
|
||||
*/
|
||||
@Nullable
|
||||
public InetAddress getGateway() {
|
||||
return mGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the interface used for this route if specified, else {@code null}.
|
||||
*
|
||||
* @return The name of the interface used for this route.
|
||||
*/
|
||||
@Nullable
|
||||
public String getInterface() {
|
||||
return mInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the type of this route.
|
||||
*
|
||||
* @return The type of this route; one of the {@code RTN_xxx} constants defined in this class.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RouteType
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the MTU size for this route.
|
||||
*
|
||||
* @return The MTU size, or 0 if it has not been set.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public int getMtu() {
|
||||
return mMtu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this route is a default route (ie, has no destination specified).
|
||||
*
|
||||
* @return {@code true} if the destination has a prefix length of 0.
|
||||
*/
|
||||
public boolean isDefaultRoute() {
|
||||
return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this route is an unreachable default route.
|
||||
*
|
||||
* @return {@code true} if it's an unreachable route with prefix length of 0.
|
||||
* @hide
|
||||
*/
|
||||
private boolean isUnreachableDefaultRoute() {
|
||||
return mType == RTN_UNREACHABLE && mDestination.getPrefixLength() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this route is an IPv4 default route.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isIPv4Default() {
|
||||
return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this route is an IPv4 unreachable default route.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isIPv4UnreachableDefault() {
|
||||
return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this route is an IPv6 default route.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isIPv6Default() {
|
||||
return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this route is an IPv6 unreachable default route.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isIPv6UnreachableDefault() {
|
||||
return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this route is a host route (ie, matches only a single host address).
|
||||
*
|
||||
* @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
|
||||
* respectively.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isHostRoute() {
|
||||
return mIsHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this route has a next hop ({@code true}) or is directly-connected
|
||||
* ({@code false}).
|
||||
*
|
||||
* @return {@code true} if a gateway is specified
|
||||
*/
|
||||
public boolean hasGateway() {
|
||||
return mHasGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the destination and prefix of this route includes the specified
|
||||
* address.
|
||||
*
|
||||
* @param destination A {@link InetAddress} to test to see if it would match this route.
|
||||
* @return {@code true} if the destination and prefix length cover the given address.
|
||||
*/
|
||||
public boolean matches(InetAddress destination) {
|
||||
return mDestination.contains(destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the route from a Collection of routes that best matches a given address.
|
||||
* May return null if no routes are applicable.
|
||||
* @param routes a Collection of RouteInfos to chose from
|
||||
* @param dest the InetAddress your trying to get to
|
||||
* @return the RouteInfo from the Collection that best fits the given address
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
@Nullable
|
||||
public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
|
||||
return NetUtils.selectBestRoute(routes, dest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human-readable description of this object.
|
||||
*/
|
||||
public String toString() {
|
||||
String val = "";
|
||||
if (mDestination != null) val = mDestination.toString();
|
||||
if (mType == RTN_UNREACHABLE) {
|
||||
val += " unreachable";
|
||||
} else if (mType == RTN_THROW) {
|
||||
val += " throw";
|
||||
} else {
|
||||
val += " ->";
|
||||
if (mGateway != null) val += " " + mGateway.getHostAddress();
|
||||
if (mInterface != null) val += " " + mInterface;
|
||||
if (mType != RTN_UNICAST) {
|
||||
val += " unknown type " + mType;
|
||||
}
|
||||
}
|
||||
val += " mtu " + mMtu;
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this RouteInfo object against the specified object and indicates if they are equal.
|
||||
* @return {@code true} if the objects are equal, {@code false} otherwise.
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
|
||||
if (!(obj instanceof RouteInfo)) return false;
|
||||
|
||||
RouteInfo target = (RouteInfo) obj;
|
||||
|
||||
return Objects.equals(mDestination, target.getDestination()) &&
|
||||
Objects.equals(mGateway, target.getGateway()) &&
|
||||
Objects.equals(mInterface, target.getInterface()) &&
|
||||
mType == target.getType() && mMtu == target.getMtu();
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper class that contains the destination, the gateway and the interface in a
|
||||
* {@code RouteInfo}, used by {@link ConnectivityService#updateRoutes} or
|
||||
* {@link LinkProperties#addRoute} to calculate the list to be updated.
|
||||
* {@code RouteInfo} objects with different interfaces are treated as different routes because
|
||||
* *usually* on Android different interfaces use different routing tables, and moving a route
|
||||
* to a new routing table never constitutes an update, but is always a remove and an add.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static class RouteKey {
|
||||
@NonNull private final IpPrefix mDestination;
|
||||
@Nullable private final InetAddress mGateway;
|
||||
@Nullable private final String mInterface;
|
||||
|
||||
RouteKey(@NonNull IpPrefix destination, @Nullable InetAddress gateway,
|
||||
@Nullable String iface) {
|
||||
mDestination = destination;
|
||||
mGateway = gateway;
|
||||
mInterface = iface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof RouteKey)) {
|
||||
return false;
|
||||
}
|
||||
RouteKey p = (RouteKey) o;
|
||||
// No need to do anything special for scoped addresses. Inet6Address#equals does not
|
||||
// consider the scope ID, but the netd route IPCs (e.g., INetd#networkAddRouteParcel)
|
||||
// and the kernel ignore scoped addresses both in the prefix and in the nexthop and only
|
||||
// look at RTA_OIF.
|
||||
return Objects.equals(p.mDestination, mDestination)
|
||||
&& Objects.equals(p.mGateway, mGateway)
|
||||
&& Objects.equals(p.mInterface, mInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mDestination, mGateway, mInterface);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@code RouteKey} of this {@code RouteInfo}.
|
||||
* @return a {@code RouteKey} object.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@NonNull
|
||||
public RouteKey getRouteKey() {
|
||||
return new RouteKey(mDestination, mGateway, mInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode for this <code>RouteInfo</code> object.
|
||||
*/
|
||||
public int hashCode() {
|
||||
return (mDestination.hashCode() * 41)
|
||||
+ (mGateway == null ? 0 :mGateway.hashCode() * 47)
|
||||
+ (mInterface == null ? 0 :mInterface.hashCode() * 67)
|
||||
+ (mType * 71) + (mMtu * 89);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface
|
||||
*/
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface
|
||||
*/
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(mDestination, flags);
|
||||
byte[] gatewayBytes = (mGateway == null) ? null : mGateway.getAddress();
|
||||
dest.writeByteArray(gatewayBytes);
|
||||
dest.writeString(mInterface);
|
||||
dest.writeInt(mType);
|
||||
dest.writeInt(mMtu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement the Parcelable interface.
|
||||
*/
|
||||
public static final @android.annotation.NonNull Creator<RouteInfo> CREATOR =
|
||||
new Creator<RouteInfo>() {
|
||||
public RouteInfo createFromParcel(Parcel in) {
|
||||
IpPrefix dest = in.readParcelable(null);
|
||||
|
||||
InetAddress gateway = null;
|
||||
byte[] addr = in.createByteArray();
|
||||
try {
|
||||
gateway = InetAddress.getByAddress(addr);
|
||||
} catch (UnknownHostException e) {}
|
||||
|
||||
String iface = in.readString();
|
||||
int type = in.readInt();
|
||||
int mtu = in.readInt();
|
||||
|
||||
return new RouteInfo(dest, gateway, iface, type, mtu);
|
||||
}
|
||||
|
||||
public RouteInfo[] newArray(int size) {
|
||||
return new RouteInfo[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
301
framework/src/android/net/SocketKeepalive.java
Normal file
301
framework/src/android/net/SocketKeepalive.java
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Binder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Allows applications to request that the system periodically send specific packets on their
|
||||
* behalf, using hardware offload to save battery power.
|
||||
*
|
||||
* To request that the system send keepalives, call one of the methods that return a
|
||||
* {@link SocketKeepalive} object, such as {@link ConnectivityManager#createSocketKeepalive},
|
||||
* passing in a non-null callback. If the {@link SocketKeepalive} is successfully
|
||||
* started, the callback's {@code onStarted} method will be called. If an error occurs,
|
||||
* {@code onError} will be called, specifying one of the {@code ERROR_*} constants in this
|
||||
* class.
|
||||
*
|
||||
* To stop an existing keepalive, call {@link SocketKeepalive#stop}. The system will call
|
||||
* {@link SocketKeepalive.Callback#onStopped} if the operation was successful or
|
||||
* {@link SocketKeepalive.Callback#onError} if an error occurred.
|
||||
*
|
||||
* For cellular, the device MUST support at least 1 keepalive slot.
|
||||
*
|
||||
* For WiFi, the device SHOULD support keepalive offload. If it does not, it MUST reply with
|
||||
* {@link SocketKeepalive.Callback#onError} with {@code ERROR_UNSUPPORTED} to any keepalive offload
|
||||
* request. If it does, it MUST support at least 3 concurrent keepalive slots.
|
||||
*/
|
||||
public abstract class SocketKeepalive implements AutoCloseable {
|
||||
static final String TAG = "SocketKeepalive";
|
||||
|
||||
/**
|
||||
* No errors.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int SUCCESS = 0;
|
||||
|
||||
/** @hide */
|
||||
public static final int NO_KEEPALIVE = -1;
|
||||
|
||||
/** @hide */
|
||||
public static final int DATA_RECEIVED = -2;
|
||||
|
||||
/** @hide */
|
||||
public static final int BINDER_DIED = -10;
|
||||
|
||||
/** The specified {@code Network} is not connected. */
|
||||
public static final int ERROR_INVALID_NETWORK = -20;
|
||||
/** The specified IP addresses are invalid. For example, the specified source IP address is
|
||||
* not configured on the specified {@code Network}. */
|
||||
public static final int ERROR_INVALID_IP_ADDRESS = -21;
|
||||
/** The requested port is invalid. */
|
||||
public static final int ERROR_INVALID_PORT = -22;
|
||||
/** The packet length is invalid (e.g., too long). */
|
||||
public static final int ERROR_INVALID_LENGTH = -23;
|
||||
/** The packet transmission interval is invalid (e.g., too short). */
|
||||
public static final int ERROR_INVALID_INTERVAL = -24;
|
||||
/** The target socket is invalid. */
|
||||
public static final int ERROR_INVALID_SOCKET = -25;
|
||||
/** The target socket is not idle. */
|
||||
public static final int ERROR_SOCKET_NOT_IDLE = -26;
|
||||
/**
|
||||
* The stop reason is uninitialized. This should only be internally used as initial state
|
||||
* of stop reason, instead of propagating to application.
|
||||
* @hide
|
||||
*/
|
||||
public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
|
||||
|
||||
/** The device does not support this request. */
|
||||
public static final int ERROR_UNSUPPORTED = -30;
|
||||
/** @hide TODO: delete when telephony code has been updated. */
|
||||
public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED;
|
||||
/** The hardware returned an error. */
|
||||
public static final int ERROR_HARDWARE_ERROR = -31;
|
||||
/** The limitation of resource is reached. */
|
||||
public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
|
||||
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(prefix = { "ERROR_" }, value = {
|
||||
ERROR_INVALID_NETWORK,
|
||||
ERROR_INVALID_IP_ADDRESS,
|
||||
ERROR_INVALID_PORT,
|
||||
ERROR_INVALID_LENGTH,
|
||||
ERROR_INVALID_INTERVAL,
|
||||
ERROR_INVALID_SOCKET,
|
||||
ERROR_SOCKET_NOT_IDLE
|
||||
})
|
||||
public @interface ErrorCode {}
|
||||
|
||||
/** @hide */
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(value = {
|
||||
SUCCESS,
|
||||
ERROR_INVALID_LENGTH,
|
||||
ERROR_UNSUPPORTED,
|
||||
ERROR_INSUFFICIENT_RESOURCES,
|
||||
ERROR_HARDWARE_UNSUPPORTED
|
||||
})
|
||||
public @interface KeepaliveEvent {}
|
||||
|
||||
/**
|
||||
* The minimum interval in seconds between keepalive packet transmissions.
|
||||
*
|
||||
* @hide
|
||||
**/
|
||||
public static final int MIN_INTERVAL_SEC = 10;
|
||||
|
||||
/**
|
||||
* The maximum interval in seconds between keepalive packet transmissions.
|
||||
*
|
||||
* @hide
|
||||
**/
|
||||
public static final int MAX_INTERVAL_SEC = 3600;
|
||||
|
||||
/**
|
||||
* An exception that embarks an error code.
|
||||
* @hide
|
||||
*/
|
||||
public static class ErrorCodeException extends Exception {
|
||||
public final int error;
|
||||
public ErrorCodeException(final int error, final Throwable e) {
|
||||
super(e);
|
||||
this.error = error;
|
||||
}
|
||||
public ErrorCodeException(final int error) {
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This socket is invalid.
|
||||
* See the error code for details, and the optional cause.
|
||||
* @hide
|
||||
*/
|
||||
public static class InvalidSocketException extends ErrorCodeException {
|
||||
public InvalidSocketException(final int error, final Throwable e) {
|
||||
super(error, e);
|
||||
}
|
||||
public InvalidSocketException(final int error) {
|
||||
super(error);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull final IConnectivityManager mService;
|
||||
@NonNull final Network mNetwork;
|
||||
@NonNull final ParcelFileDescriptor mPfd;
|
||||
@NonNull final Executor mExecutor;
|
||||
@NonNull final ISocketKeepaliveCallback mCallback;
|
||||
// TODO: remove slot since mCallback could be used to identify which keepalive to stop.
|
||||
@Nullable Integer mSlot;
|
||||
|
||||
SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
|
||||
@NonNull ParcelFileDescriptor pfd,
|
||||
@NonNull Executor executor, @NonNull Callback callback) {
|
||||
mService = service;
|
||||
mNetwork = network;
|
||||
mPfd = pfd;
|
||||
mExecutor = executor;
|
||||
mCallback = new ISocketKeepaliveCallback.Stub() {
|
||||
@Override
|
||||
public void onStarted(int slot) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mExecutor.execute(() -> {
|
||||
mSlot = slot;
|
||||
callback.onStarted();
|
||||
});
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopped() {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> {
|
||||
mSlot = null;
|
||||
callback.onStopped();
|
||||
});
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int error) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> {
|
||||
mSlot = null;
|
||||
callback.onError(error);
|
||||
});
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataReceived() {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> {
|
||||
mSlot = null;
|
||||
callback.onDataReceived();
|
||||
});
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that keepalive be started with the given {@code intervalSec}. See
|
||||
* {@link SocketKeepalive}. If the remote binder dies, or the binder call throws an exception
|
||||
* when invoking start or stop of the {@link SocketKeepalive}, a {@link RemoteException} will be
|
||||
* thrown into the {@code executor}. This is typically not important to catch because the remote
|
||||
* party is the system, so if it is not in shape to communicate through binder the system is
|
||||
* probably going down anyway. If the caller cares regardless, it can use a custom
|
||||
* {@link Executor} to catch the {@link RemoteException}.
|
||||
*
|
||||
* @param intervalSec The target interval in seconds between keepalive packet transmissions.
|
||||
* The interval should be between 10 seconds and 3600 seconds, otherwise
|
||||
* {@link #ERROR_INVALID_INTERVAL} will be returned.
|
||||
*/
|
||||
public final void start(@IntRange(from = MIN_INTERVAL_SEC, to = MAX_INTERVAL_SEC)
|
||||
int intervalSec) {
|
||||
startImpl(intervalSec);
|
||||
}
|
||||
|
||||
abstract void startImpl(int intervalSec);
|
||||
|
||||
/**
|
||||
* Requests that keepalive be stopped. The application must wait for {@link Callback#onStopped}
|
||||
* before using the object. See {@link SocketKeepalive}.
|
||||
*/
|
||||
public final void stop() {
|
||||
stopImpl();
|
||||
}
|
||||
|
||||
abstract void stopImpl();
|
||||
|
||||
/**
|
||||
* Deactivate this {@link SocketKeepalive} and free allocated resources. The instance won't be
|
||||
* usable again if {@code close()} is called.
|
||||
*/
|
||||
@Override
|
||||
public final void close() {
|
||||
stop();
|
||||
try {
|
||||
mPfd.close();
|
||||
} catch (IOException e) {
|
||||
// Nothing much can be done.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The callback which app can use to learn the status changes of {@link SocketKeepalive}. See
|
||||
* {@link SocketKeepalive}.
|
||||
*/
|
||||
public static class Callback {
|
||||
/** The requested keepalive was successfully started. */
|
||||
public void onStarted() {}
|
||||
/** The keepalive was successfully stopped. */
|
||||
public void onStopped() {}
|
||||
/** An error occurred. */
|
||||
public void onError(@ErrorCode int error) {}
|
||||
/** The keepalive on a TCP socket was stopped because the socket received data. This is
|
||||
* never called for UDP sockets. */
|
||||
public void onDataReceived() {}
|
||||
}
|
||||
}
|
||||
20
framework/src/android/net/StaticIpConfiguration.aidl
Normal file
20
framework/src/android/net/StaticIpConfiguration.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2019 The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable StaticIpConfiguration;
|
||||
332
framework/src/android/net/StaticIpConfiguration.java
Normal file
332
framework/src/android/net/StaticIpConfiguration.java
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.net.module.util.InetAddressUtils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Class that describes static IP configuration.
|
||||
*
|
||||
* <p>This class is different from {@link LinkProperties} because it represents
|
||||
* configuration intent. The general contract is that if we can represent
|
||||
* a configuration here, then we should be able to configure it on a network.
|
||||
* The intent is that it closely match the UI we have for configuring networks.
|
||||
*
|
||||
* <p>In contrast, {@link LinkProperties} represents current state. It is much more
|
||||
* expressive. For example, it supports multiple IP addresses, multiple routes,
|
||||
* stacked interfaces, and so on. Because LinkProperties is so expressive,
|
||||
* using it to represent configuration intent as well as current state causes
|
||||
* problems. For example, we could unknowingly save a configuration that we are
|
||||
* not in fact capable of applying, or we could save a configuration that the
|
||||
* UI cannot display, which has the potential for malicious code to hide
|
||||
* hostile or unexpected configuration from the user.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class StaticIpConfiguration implements Parcelable {
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
@Nullable
|
||||
public LinkAddress ipAddress;
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
@Nullable
|
||||
public InetAddress gateway;
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
@NonNull
|
||||
public final ArrayList<InetAddress> dnsServers;
|
||||
/** @hide */
|
||||
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
||||
@Nullable
|
||||
public String domains;
|
||||
|
||||
public StaticIpConfiguration() {
|
||||
dnsServers = new ArrayList<>();
|
||||
}
|
||||
|
||||
public StaticIpConfiguration(@Nullable StaticIpConfiguration source) {
|
||||
this();
|
||||
if (source != null) {
|
||||
// All of these except dnsServers are immutable, so no need to make copies.
|
||||
ipAddress = source.ipAddress;
|
||||
gateway = source.gateway;
|
||||
dnsServers.addAll(source.dnsServers);
|
||||
domains = source.domains;
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
ipAddress = null;
|
||||
gateway = null;
|
||||
dnsServers.clear();
|
||||
domains = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the static IP address included in the configuration.
|
||||
*/
|
||||
public @Nullable LinkAddress getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the gateway included in the configuration.
|
||||
*/
|
||||
public @Nullable InetAddress getGateway() {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DNS servers included in the configuration.
|
||||
*/
|
||||
public @NonNull List<InetAddress> getDnsServers() {
|
||||
return dnsServers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a {@link String} containing the comma separated domains to search when resolving host
|
||||
* names on this link, in priority order.
|
||||
*/
|
||||
public @Nullable String getDomains() {
|
||||
return domains;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to build a new instance of {@link StaticIpConfiguration}.
|
||||
*/
|
||||
public static final class Builder {
|
||||
private LinkAddress mIpAddress;
|
||||
private InetAddress mGateway;
|
||||
private Iterable<InetAddress> mDnsServers;
|
||||
private String mDomains;
|
||||
|
||||
/**
|
||||
* Set the IP address to be included in the configuration; null by default.
|
||||
* @return The {@link Builder} for chaining.
|
||||
*/
|
||||
public @NonNull Builder setIpAddress(@Nullable LinkAddress ipAddress) {
|
||||
mIpAddress = ipAddress;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address of the gateway to be included in the configuration; null by default.
|
||||
* @return The {@link Builder} for chaining.
|
||||
*/
|
||||
public @NonNull Builder setGateway(@Nullable InetAddress gateway) {
|
||||
mGateway = gateway;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the addresses of the DNS servers included in the configuration; empty by default.
|
||||
* @return The {@link Builder} for chaining.
|
||||
*/
|
||||
public @NonNull Builder setDnsServers(@NonNull Iterable<InetAddress> dnsServers) {
|
||||
Preconditions.checkNotNull(dnsServers);
|
||||
mDnsServers = dnsServers;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DNS domain search path to be used on the link; null by default.
|
||||
* @param newDomains A {@link String} containing the comma separated domains to search when
|
||||
* resolving host names on this link, in priority order.
|
||||
* @return The {@link Builder} for chaining.
|
||||
*/
|
||||
public @NonNull Builder setDomains(@Nullable String newDomains) {
|
||||
mDomains = newDomains;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link StaticIpConfiguration} from the parameters in this {@link Builder}.
|
||||
* @return The newly created StaticIpConfiguration.
|
||||
*/
|
||||
public @NonNull StaticIpConfiguration build() {
|
||||
final StaticIpConfiguration config = new StaticIpConfiguration();
|
||||
config.ipAddress = mIpAddress;
|
||||
config.gateway = mGateway;
|
||||
if (mDnsServers != null) {
|
||||
for (InetAddress server : mDnsServers) {
|
||||
config.dnsServers.add(server);
|
||||
}
|
||||
}
|
||||
config.domains = mDomains;
|
||||
return config;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a DNS server to this configuration.
|
||||
*/
|
||||
public void addDnsServer(@NonNull InetAddress server) {
|
||||
dnsServers.add(server);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the network routes specified by this object. Will typically include a
|
||||
* directly-connected route for the IP address's local subnet and a default route.
|
||||
* @param iface Interface to include in the routes.
|
||||
*/
|
||||
public @NonNull List<RouteInfo> getRoutes(@Nullable String iface) {
|
||||
List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
|
||||
if (ipAddress != null) {
|
||||
RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface);
|
||||
routes.add(connectedRoute);
|
||||
// If the default gateway is not covered by the directly-connected route, also add a
|
||||
// host route to the gateway as well. This configuration is arguably invalid, but it
|
||||
// used to work in K and earlier, and other OSes appear to accept it.
|
||||
if (gateway != null && !connectedRoute.matches(gateway)) {
|
||||
routes.add(RouteInfo.makeHostRoute(gateway, iface));
|
||||
}
|
||||
}
|
||||
if (gateway != null) {
|
||||
routes.add(new RouteInfo((IpPrefix) null, gateway, iface));
|
||||
}
|
||||
return routes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a LinkProperties object expressing the data in this object. Note that the information
|
||||
* contained in the LinkProperties will not be a complete picture of the link's configuration,
|
||||
* because any configuration information that is obtained dynamically by the network (e.g.,
|
||||
* IPv6 configuration) will not be included.
|
||||
* @hide
|
||||
*/
|
||||
public @NonNull LinkProperties toLinkProperties(String iface) {
|
||||
LinkProperties lp = new LinkProperties();
|
||||
lp.setInterfaceName(iface);
|
||||
if (ipAddress != null) {
|
||||
lp.addLinkAddress(ipAddress);
|
||||
}
|
||||
for (RouteInfo route : getRoutes(iface)) {
|
||||
lp.addRoute(route);
|
||||
}
|
||||
for (InetAddress dns : dnsServers) {
|
||||
lp.addDnsServer(dns);
|
||||
}
|
||||
lp.setDomains(domains);
|
||||
return lp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer str = new StringBuffer();
|
||||
|
||||
str.append("IP address ");
|
||||
if (ipAddress != null ) str.append(ipAddress).append(" ");
|
||||
|
||||
str.append("Gateway ");
|
||||
if (gateway != null) str.append(gateway.getHostAddress()).append(" ");
|
||||
|
||||
str.append(" DNS servers: [");
|
||||
for (InetAddress dnsServer : dnsServers) {
|
||||
str.append(" ").append(dnsServer.getHostAddress());
|
||||
}
|
||||
|
||||
str.append(" ] Domains ");
|
||||
if (domains != null) str.append(domains);
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 13;
|
||||
result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode());
|
||||
result = 47 * result + (gateway == null ? 0 : gateway.hashCode());
|
||||
result = 47 * result + (domains == null ? 0 : domains.hashCode());
|
||||
result = 47 * result + dnsServers.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) return true;
|
||||
|
||||
if (!(obj instanceof StaticIpConfiguration)) return false;
|
||||
|
||||
StaticIpConfiguration other = (StaticIpConfiguration) obj;
|
||||
|
||||
return other != null &&
|
||||
Objects.equals(ipAddress, other.ipAddress) &&
|
||||
Objects.equals(gateway, other.gateway) &&
|
||||
dnsServers.equals(other.dnsServers) &&
|
||||
Objects.equals(domains, other.domains);
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
public static final @android.annotation.NonNull Creator<StaticIpConfiguration> CREATOR =
|
||||
new Creator<StaticIpConfiguration>() {
|
||||
public StaticIpConfiguration createFromParcel(Parcel in) {
|
||||
return readFromParcel(in);
|
||||
}
|
||||
|
||||
public StaticIpConfiguration[] newArray(int size) {
|
||||
return new StaticIpConfiguration[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(ipAddress, flags);
|
||||
InetAddressUtils.parcelInetAddress(dest, gateway, flags);
|
||||
dest.writeInt(dnsServers.size());
|
||||
for (InetAddress dnsServer : dnsServers) {
|
||||
InetAddressUtils.parcelInetAddress(dest, dnsServer, flags);
|
||||
}
|
||||
dest.writeString(domains);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static StaticIpConfiguration readFromParcel(Parcel in) {
|
||||
final StaticIpConfiguration s = new StaticIpConfiguration();
|
||||
s.ipAddress = in.readParcelable(null);
|
||||
s.gateway = InetAddressUtils.unparcelInetAddress(in);
|
||||
s.dnsServers.clear();
|
||||
int size = in.readInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
s.dnsServers.add(InetAddressUtils.unparcelInetAddress(in));
|
||||
}
|
||||
s.domains = in.readString();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
163
framework/src/android/net/TcpKeepalivePacketData.java
Normal file
163
framework/src/android/net/TcpKeepalivePacketData.java
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents the actual tcp keep alive packets which will be used for hardware offload.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable {
|
||||
private static final String TAG = "TcpKeepalivePacketData";
|
||||
|
||||
/** TCP sequence number. */
|
||||
public final int tcpSeq;
|
||||
|
||||
/** TCP ACK number. */
|
||||
public final int tcpAck;
|
||||
|
||||
/** TCP RCV window. */
|
||||
public final int tcpWindow;
|
||||
|
||||
/** TCP RCV window scale. */
|
||||
public final int tcpWindowScale;
|
||||
|
||||
/** IP TOS. */
|
||||
public final int ipTos;
|
||||
|
||||
/** IP TTL. */
|
||||
public final int ipTtl;
|
||||
|
||||
public TcpKeepalivePacketData(@NonNull final InetAddress srcAddress, int srcPort,
|
||||
@NonNull final InetAddress dstAddress, int dstPort, @NonNull final byte[] data,
|
||||
int tcpSeq, int tcpAck, int tcpWindow, int tcpWindowScale, int ipTos, int ipTtl)
|
||||
throws InvalidPacketException {
|
||||
super(srcAddress, srcPort, dstAddress, dstPort, data);
|
||||
this.tcpSeq = tcpSeq;
|
||||
this.tcpAck = tcpAck;
|
||||
this.tcpWindow = tcpWindow;
|
||||
this.tcpWindowScale = tcpWindowScale;
|
||||
this.ipTos = ipTos;
|
||||
this.ipTtl = ipTtl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable final Object o) {
|
||||
if (!(o instanceof TcpKeepalivePacketData)) return false;
|
||||
final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o;
|
||||
final InetAddress srcAddress = getSrcAddress();
|
||||
final InetAddress dstAddress = getDstAddress();
|
||||
return srcAddress.equals(other.getSrcAddress())
|
||||
&& dstAddress.equals(other.getDstAddress())
|
||||
&& getSrcPort() == other.getSrcPort()
|
||||
&& getDstPort() == other.getDstPort()
|
||||
&& this.tcpAck == other.tcpAck
|
||||
&& this.tcpSeq == other.tcpSeq
|
||||
&& this.tcpWindow == other.tcpWindow
|
||||
&& this.tcpWindowScale == other.tcpWindowScale
|
||||
&& this.ipTos == other.ipTos
|
||||
&& this.ipTtl == other.ipTtl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort(),
|
||||
tcpAck, tcpSeq, tcpWindow, tcpWindowScale, ipTos, ipTtl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcelable Implementation.
|
||||
* Note that this object implements parcelable (and needs to keep doing this as it inherits
|
||||
* from a class that does), but should usually be parceled as a stable parcelable using
|
||||
* the toStableParcelable() and fromStableParcelable() methods.
|
||||
*/
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Write to parcel. */
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel out, int flags) {
|
||||
out.writeString(getSrcAddress().getHostAddress());
|
||||
out.writeString(getDstAddress().getHostAddress());
|
||||
out.writeInt(getSrcPort());
|
||||
out.writeInt(getDstPort());
|
||||
out.writeByteArray(getPacket());
|
||||
out.writeInt(tcpSeq);
|
||||
out.writeInt(tcpAck);
|
||||
out.writeInt(tcpWindow);
|
||||
out.writeInt(tcpWindowScale);
|
||||
out.writeInt(ipTos);
|
||||
out.writeInt(ipTtl);
|
||||
}
|
||||
|
||||
private static TcpKeepalivePacketData readFromParcel(Parcel in) throws InvalidPacketException {
|
||||
InetAddress srcAddress = InetAddresses.parseNumericAddress(in.readString());
|
||||
InetAddress dstAddress = InetAddresses.parseNumericAddress(in.readString());
|
||||
int srcPort = in.readInt();
|
||||
int dstPort = in.readInt();
|
||||
byte[] packet = in.createByteArray();
|
||||
int tcpSeq = in.readInt();
|
||||
int tcpAck = in.readInt();
|
||||
int tcpWnd = in.readInt();
|
||||
int tcpWndScale = in.readInt();
|
||||
int ipTos = in.readInt();
|
||||
int ipTtl = in.readInt();
|
||||
return new TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, packet, tcpSeq,
|
||||
tcpAck, tcpWnd, tcpWndScale, ipTos, ipTtl);
|
||||
}
|
||||
|
||||
/** Parcelable Creator. */
|
||||
public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
|
||||
new Parcelable.Creator<TcpKeepalivePacketData>() {
|
||||
public TcpKeepalivePacketData createFromParcel(Parcel in) {
|
||||
try {
|
||||
return readFromParcel(in);
|
||||
} catch (InvalidPacketException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid TCP keepalive data: " + e.getError());
|
||||
}
|
||||
}
|
||||
|
||||
public TcpKeepalivePacketData[] newArray(int size) {
|
||||
return new TcpKeepalivePacketData[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "saddr: " + getSrcAddress()
|
||||
+ " daddr: " + getDstAddress()
|
||||
+ " sport: " + getSrcPort()
|
||||
+ " dport: " + getDstPort()
|
||||
+ " seq: " + tcpSeq
|
||||
+ " ack: " + tcpAck
|
||||
+ " window: " + tcpWindow
|
||||
+ " windowScale: " + tcpWindowScale
|
||||
+ " tos: " + ipTos
|
||||
+ " ttl: " + ipTtl;
|
||||
}
|
||||
}
|
||||
48
framework/src/android/net/TcpRepairWindow.java
Normal file
48
framework/src/android/net/TcpRepairWindow.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.SystemApi;
|
||||
|
||||
/**
|
||||
* Corresponds to C's {@code struct tcp_repair_window} from
|
||||
* include/uapi/linux/tcp.h
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
|
||||
public final class TcpRepairWindow {
|
||||
public final int sndWl1;
|
||||
public final int sndWnd;
|
||||
public final int maxWindow;
|
||||
public final int rcvWnd;
|
||||
public final int rcvWup;
|
||||
public final int rcvWndScale;
|
||||
|
||||
/**
|
||||
* Constructs an instance with the given field values.
|
||||
*/
|
||||
public TcpRepairWindow(final int sndWl1, final int sndWnd, final int maxWindow,
|
||||
final int rcvWnd, final int rcvWup, final int rcvWndScale) {
|
||||
this.sndWl1 = sndWl1;
|
||||
this.sndWnd = sndWnd;
|
||||
this.maxWindow = maxWindow;
|
||||
this.rcvWnd = rcvWnd;
|
||||
this.rcvWup = rcvWup;
|
||||
this.rcvWndScale = rcvWndScale;
|
||||
}
|
||||
}
|
||||
77
framework/src/android/net/TcpSocketKeepalive.java
Normal file
77
framework/src/android/net/TcpSocketKeepalive.java
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/** @hide */
|
||||
final class TcpSocketKeepalive extends SocketKeepalive {
|
||||
|
||||
TcpSocketKeepalive(@NonNull IConnectivityManager service,
|
||||
@NonNull Network network,
|
||||
@NonNull ParcelFileDescriptor pfd,
|
||||
@NonNull Executor executor,
|
||||
@NonNull Callback callback) {
|
||||
super(service, network, pfd, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts keepalives. {@code mSocket} must be a connected TCP socket.
|
||||
*
|
||||
* - The application must not write to or read from the socket after calling this method, until
|
||||
* onDataReceived, onStopped, or onError are called. If it does, the keepalive will fail
|
||||
* with {@link #ERROR_SOCKET_NOT_IDLE}, or {@code #ERROR_INVALID_SOCKET} if the socket
|
||||
* experienced an error (as in poll(2) returned POLLERR or POLLHUP); if this happens, the data
|
||||
* received from the socket may be invalid, and the socket can't be recovered.
|
||||
* - If the socket has data in the send or receive buffer, then this call will fail with
|
||||
* {@link #ERROR_SOCKET_NOT_IDLE} and can be retried after the data has been processed.
|
||||
* An app could ensure this by using an application-layer protocol to receive acknowledgement
|
||||
* that indicates all data has been delivered to server, e.g. HTTP 200 OK.
|
||||
* Then the app could go into keepalive mode after reading all remaining data within the
|
||||
* acknowledgement.
|
||||
*/
|
||||
@Override
|
||||
void startImpl(int intervalSec) {
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error starting packet keepalive: ", e);
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
void stopImpl() {
|
||||
mExecutor.execute(() -> {
|
||||
try {
|
||||
if (mSlot != null) {
|
||||
mService.stopKeepalive(mNetwork, mSlot);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Error stopping packet keepalive: ", e);
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
20
framework/src/android/net/TestNetworkInterface.aidl
Normal file
20
framework/src/android/net/TestNetworkInterface.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
/** @hide */
|
||||
parcelable TestNetworkInterface;
|
||||
78
framework/src/android/net/TestNetworkInterface.java
Normal file
78
framework/src/android/net/TestNetworkInterface.java
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* This class is used to return the interface name and fd of the test interface
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
|
||||
public final class TestNetworkInterface implements Parcelable {
|
||||
@NonNull
|
||||
private final ParcelFileDescriptor mFileDescriptor;
|
||||
@NonNull
|
||||
private final String mInterfaceName;
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return (mFileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel out, int flags) {
|
||||
out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE);
|
||||
out.writeString(mInterfaceName);
|
||||
}
|
||||
|
||||
public TestNetworkInterface(@NonNull ParcelFileDescriptor pfd, @NonNull String intf) {
|
||||
mFileDescriptor = pfd;
|
||||
mInterfaceName = intf;
|
||||
}
|
||||
|
||||
private TestNetworkInterface(@NonNull Parcel in) {
|
||||
mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
|
||||
mInterfaceName = in.readString();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ParcelFileDescriptor getFileDescriptor() {
|
||||
return mFileDescriptor;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getInterfaceName() {
|
||||
return mInterfaceName;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<TestNetworkInterface> CREATOR =
|
||||
new Parcelable.Creator<TestNetworkInterface>() {
|
||||
public TestNetworkInterface createFromParcel(Parcel in) {
|
||||
return new TestNetworkInterface(in);
|
||||
}
|
||||
|
||||
public TestNetworkInterface[] newArray(int size) {
|
||||
return new TestNetworkInterface[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
178
framework/src/android/net/TestNetworkManager.java
Normal file
178
framework/src/android/net/TestNetworkManager.java
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Class that allows creation and management of per-app, test-only networks
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
|
||||
public class TestNetworkManager {
|
||||
/**
|
||||
* Prefix for tun interfaces created by this class.
|
||||
* @hide
|
||||
*/
|
||||
public static final String TEST_TUN_PREFIX = "testtun";
|
||||
|
||||
/**
|
||||
* Prefix for tap interfaces created by this class.
|
||||
* @hide
|
||||
*/
|
||||
public static final String TEST_TAP_PREFIX = "testtap";
|
||||
|
||||
@NonNull private static final String TAG = TestNetworkManager.class.getSimpleName();
|
||||
|
||||
@NonNull private final ITestNetworkManager mService;
|
||||
|
||||
/** @hide */
|
||||
public TestNetworkManager(@NonNull ITestNetworkManager service) {
|
||||
mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager");
|
||||
}
|
||||
|
||||
/**
|
||||
* Teardown the capability-limited, testing-only network for a given interface
|
||||
*
|
||||
* @param network The test network that should be torn down
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
|
||||
public void teardownTestNetwork(@NonNull Network network) {
|
||||
try {
|
||||
mService.teardownTestNetwork(network.netId);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupTestNetwork(
|
||||
@NonNull String iface,
|
||||
@Nullable LinkProperties lp,
|
||||
boolean isMetered,
|
||||
@NonNull int[] administratorUids,
|
||||
@NonNull IBinder binder) {
|
||||
try {
|
||||
mService.setupTestNetwork(iface, lp, isMetered, administratorUids, binder);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a capability-limited, testing-only network for a given interface
|
||||
*
|
||||
* @param lp The LinkProperties for the TestNetworkService to use for this test network. Note
|
||||
* that the interface name and link addresses will be overwritten, and the passed-in values
|
||||
* discarded.
|
||||
* @param isMetered Whether or not the network should be considered metered.
|
||||
* @param binder A binder object guarding the lifecycle of this test network.
|
||||
* @hide
|
||||
*/
|
||||
public void setupTestNetwork(
|
||||
@NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) {
|
||||
Preconditions.checkNotNull(lp, "Invalid LinkProperties");
|
||||
setupTestNetwork(lp.getInterfaceName(), lp, isMetered, new int[0], binder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a capability-limited, testing-only network for a given interface
|
||||
*
|
||||
* @param iface the name of the interface to be used for the Network LinkProperties.
|
||||
* @param binder A binder object guarding the lifecycle of this test network.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
|
||||
public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) {
|
||||
setupTestNetwork(iface, null, true, new int[0], binder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a capability-limited, testing-only network for a given interface with the given
|
||||
* administrator UIDs.
|
||||
*
|
||||
* @param iface the name of the interface to be used for the Network LinkProperties.
|
||||
* @param administratorUids The administrator UIDs to be used for the test-only network
|
||||
* @param binder A binder object guarding the lifecycle of this test network.
|
||||
* @hide
|
||||
*/
|
||||
public void setupTestNetwork(
|
||||
@NonNull String iface, @NonNull int[] administratorUids, @NonNull IBinder binder) {
|
||||
setupTestNetwork(iface, null, true, administratorUids, binder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tun interface for testing purposes
|
||||
*
|
||||
* @param linkAddrs an array of LinkAddresses to assign to the TUN interface
|
||||
* @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
|
||||
* TUN interface.
|
||||
* @deprecated Use {@link #createTunInterface(Collection)} instead.
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@NonNull
|
||||
public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
|
||||
return createTunInterface(Arrays.asList(linkAddrs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tun interface for testing purposes
|
||||
*
|
||||
* @param linkAddrs an array of LinkAddresses to assign to the TUN interface
|
||||
* @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the
|
||||
* TUN interface.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
|
||||
@NonNull
|
||||
public TestNetworkInterface createTunInterface(@NonNull Collection<LinkAddress> linkAddrs) {
|
||||
try {
|
||||
final LinkAddress[] arr = new LinkAddress[linkAddrs.size()];
|
||||
return mService.createTunInterface(linkAddrs.toArray(arr));
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a tap interface for testing purposes
|
||||
*
|
||||
* @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the
|
||||
* TAP interface.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
|
||||
@NonNull
|
||||
public TestNetworkInterface createTapInterface() {
|
||||
try {
|
||||
return mService.createTapInterface();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
63
framework/src/android/net/TransportInfo.java
Normal file
63
framework/src/android/net/TransportInfo.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
|
||||
/**
|
||||
* A container for transport-specific capabilities which is returned by
|
||||
* {@link NetworkCapabilities#getTransportInfo()}. Specific networks
|
||||
* may provide concrete implementations of this interface.
|
||||
* @see android.net.wifi.aware.WifiAwareNetworkInfo
|
||||
* @see android.net.wifi.WifiInfo
|
||||
*/
|
||||
public interface TransportInfo {
|
||||
|
||||
/**
|
||||
* Create a copy of a {@link TransportInfo} that will preserve location sensitive fields that
|
||||
* were set based on the permissions of the process that originally received it.
|
||||
*
|
||||
* <p>By default {@link TransportInfo} does not preserve such fields during parceling, as
|
||||
* they should not be shared outside of the process that receives them without appropriate
|
||||
* checks.
|
||||
*
|
||||
* @param parcelLocationSensitiveFields Whether the location sensitive fields should be kept
|
||||
* when parceling
|
||||
* @return Copy of this instance.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@NonNull
|
||||
default TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this TransportInfo type has location sensitive fields or not (helps
|
||||
* to determine whether to perform a location permission check or not before sending to
|
||||
* apps).
|
||||
*
|
||||
* @return {@code true} if this instance contains location sensitive info, {@code false}
|
||||
* otherwise.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
default boolean hasLocationSensitiveFields() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
24
framework/src/android/net/UidRange.aidl
Normal file
24
framework/src/android/net/UidRange.aidl
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
/**
|
||||
* An inclusive range of UIDs.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
parcelable UidRange;
|
||||
164
framework/src/android/net/VpnManager.java
Normal file
164
framework/src/android/net/VpnManager.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.android.internal.net.VpnProfile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* This class provides an interface for apps to manage platform VPN profiles
|
||||
*
|
||||
* <p>Apps can use this API to provide profiles with which the platform can set up a VPN without
|
||||
* further app intermediation. When a VPN profile is present and the app is selected as an always-on
|
||||
* VPN, the platform will directly trigger the negotiation of the VPN without starting or waking the
|
||||
* app (unlike VpnService).
|
||||
*
|
||||
* <p>VPN apps using supported protocols should preferentially use this API over the {@link
|
||||
* VpnService} API for ease-of-development and reduced maintainance burden. This also give the user
|
||||
* the guarantee that VPN network traffic is not subjected to on-device packet interception.
|
||||
*
|
||||
* @see Ikev2VpnProfile
|
||||
*/
|
||||
public class VpnManager {
|
||||
/** Type representing a lack of VPN @hide */
|
||||
public static final int TYPE_VPN_NONE = -1;
|
||||
/** VPN service type code @hide */
|
||||
public static final int TYPE_VPN_SERVICE = 1;
|
||||
/** Platform VPN type code @hide */
|
||||
public static final int TYPE_VPN_PLATFORM = 2;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface VpnType {}
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final IConnectivityManager mService;
|
||||
|
||||
private static Intent getIntentForConfirmation() {
|
||||
final Intent intent = new Intent();
|
||||
final ComponentName componentName = ComponentName.unflattenFromString(
|
||||
Resources.getSystem().getString(
|
||||
com.android.internal.R.string.config_platformVpnConfirmDialogComponent));
|
||||
intent.setComponent(componentName);
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of the VpnManager with the given context.
|
||||
*
|
||||
* <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the
|
||||
* {@link Context.getSystemService()} method call.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) {
|
||||
mContext = checkNotNull(ctx, "missing Context");
|
||||
mService = checkNotNull(service, "missing IConnectivityManager");
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a VpnProfile configuration keyed on the calling app's package name.
|
||||
*
|
||||
* <p>This method returns {@code null} if user consent has already been granted, or an {@link
|
||||
* Intent} to a system activity. If an intent is returned, the application should launch the
|
||||
* activity using {@link Activity#startActivityForResult} to request user consent. The activity
|
||||
* may pop up a dialog to require user action, and the result will come back via its {@link
|
||||
* Activity#onActivityResult}. If the result is {@link Activity#RESULT_OK}, the user has
|
||||
* consented, and the VPN profile can be started.
|
||||
*
|
||||
* @param profile the VpnProfile provided by this package. Will override any previous VpnProfile
|
||||
* stored for this package.
|
||||
* @return an Intent requesting user consent to start the VPN, or null if consent is not
|
||||
* required based on privileges or previous user consent.
|
||||
*/
|
||||
@Nullable
|
||||
public Intent provisionVpnProfile(@NonNull PlatformVpnProfile profile) {
|
||||
final VpnProfile internalProfile;
|
||||
|
||||
try {
|
||||
internalProfile = profile.toVpnProfile();
|
||||
} catch (GeneralSecurityException | IOException e) {
|
||||
// Conversion to VpnProfile failed; this is an invalid profile. Both of these exceptions
|
||||
// indicate a failure to convert a PrivateKey or X509Certificate to a Base64 encoded
|
||||
// string as required by the VpnProfile.
|
||||
throw new IllegalArgumentException("Failed to serialize PlatformVpnProfile", e);
|
||||
}
|
||||
|
||||
try {
|
||||
// Profile can never be null; it either gets set, or an exception is thrown.
|
||||
if (mService.provisionVpnProfile(internalProfile, mContext.getOpPackageName())) {
|
||||
return null;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
return getIntentForConfirmation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the VPN profile configuration that was provisioned by the calling app
|
||||
*
|
||||
* @throws SecurityException if this would violate user settings
|
||||
*/
|
||||
public void deleteProvisionedVpnProfile() {
|
||||
try {
|
||||
mService.deleteVpnProfile(mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the startup of a previously provisioned VPN.
|
||||
*
|
||||
* @throws SecurityException exception if user or device settings prevent this VPN from being
|
||||
* setup, or if user consent has not been granted
|
||||
*/
|
||||
public void startProvisionedVpnProfile() {
|
||||
try {
|
||||
mService.startVpnProfile(mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/** Tear down the VPN provided by the calling app (if any) */
|
||||
public void stopProvisionedVpnProfile() {
|
||||
try {
|
||||
mService.stopVpnProfile(mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
903
framework/src/android/net/VpnService.java
Normal file
903
framework/src/android/net/VpnService.java
Normal file
@@ -0,0 +1,903 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net;
|
||||
|
||||
import static android.system.OsConstants.AF_INET;
|
||||
import static android.system.OsConstants.AF_INET6;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.compat.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.internal.net.VpnConfig;
|
||||
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* VpnService is a base class for applications to extend and build their
|
||||
* own VPN solutions. In general, it creates a virtual network interface,
|
||||
* configures addresses and routing rules, and returns a file descriptor
|
||||
* to the application. Each read from the descriptor retrieves an outgoing
|
||||
* packet which was routed to the interface. Each write to the descriptor
|
||||
* injects an incoming packet just like it was received from the interface.
|
||||
* The interface is running on Internet Protocol (IP), so packets are
|
||||
* always started with IP headers. The application then completes a VPN
|
||||
* connection by processing and exchanging packets with the remote server
|
||||
* over a tunnel.
|
||||
*
|
||||
* <p>Letting applications intercept packets raises huge security concerns.
|
||||
* A VPN application can easily break the network. Besides, two of them may
|
||||
* conflict with each other. The system takes several actions to address
|
||||
* these issues. Here are some key points:
|
||||
* <ul>
|
||||
* <li>User action is required the first time an application creates a VPN
|
||||
* connection.</li>
|
||||
* <li>There can be only one VPN connection running at the same time. The
|
||||
* existing interface is deactivated when a new one is created.</li>
|
||||
* <li>A system-managed notification is shown during the lifetime of a
|
||||
* VPN connection.</li>
|
||||
* <li>A system-managed dialog gives the information of the current VPN
|
||||
* connection. It also provides a button to disconnect.</li>
|
||||
* <li>The network is restored automatically when the file descriptor is
|
||||
* closed. It also covers the cases when a VPN application is crashed
|
||||
* or killed by the system.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>There are two primary methods in this class: {@link #prepare} and
|
||||
* {@link Builder#establish}. The former deals with user action and stops
|
||||
* the VPN connection created by another application. The latter creates
|
||||
* a VPN interface using the parameters supplied to the {@link Builder}.
|
||||
* An application must call {@link #prepare} to grant the right to use
|
||||
* other methods in this class, and the right can be revoked at any time.
|
||||
* Here are the general steps to create a VPN connection:
|
||||
* <ol>
|
||||
* <li>When the user presses the button to connect, call {@link #prepare}
|
||||
* and launch the returned intent, if non-null.</li>
|
||||
* <li>When the application becomes prepared, start the service.</li>
|
||||
* <li>Create a tunnel to the remote server and negotiate the network
|
||||
* parameters for the VPN connection.</li>
|
||||
* <li>Supply those parameters to a {@link Builder} and create a VPN
|
||||
* interface by calling {@link Builder#establish}.</li>
|
||||
* <li>Process and exchange packets between the tunnel and the returned
|
||||
* file descriptor.</li>
|
||||
* <li>When {@link #onRevoke} is invoked, close the file descriptor and
|
||||
* shut down the tunnel gracefully.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>Services extending this class need to be declared with an appropriate
|
||||
* permission and intent filter. Their access must be secured by
|
||||
* {@link android.Manifest.permission#BIND_VPN_SERVICE} permission, and
|
||||
* their intent filter must match {@link #SERVICE_INTERFACE} action. Here
|
||||
* is an example of declaring a VPN service in {@code AndroidManifest.xml}:
|
||||
* <pre>
|
||||
* <service android:name=".ExampleVpnService"
|
||||
* android:permission="android.permission.BIND_VPN_SERVICE">
|
||||
* <intent-filter>
|
||||
* <action android:name="android.net.VpnService"/>
|
||||
* </intent-filter>
|
||||
* </service></pre>
|
||||
*
|
||||
* <p> The Android system starts a VPN in the background by calling
|
||||
* {@link android.content.Context#startService startService()}. In Android 8.0
|
||||
* (API level 26) and higher, the system places VPN apps on the temporary
|
||||
* allowlist for a short period so the app can start in the background. The VPN
|
||||
* app must promote itself to the foreground after it's launched or the system
|
||||
* will shut down the app.
|
||||
*
|
||||
* <h3>Developer's guide</h3>
|
||||
*
|
||||
* <p>To learn more about developing VPN apps, read the
|
||||
* <a href="{@docRoot}guide/topics/connectivity/vpn">VPN developer's guide</a>.
|
||||
*
|
||||
* @see Builder
|
||||
*/
|
||||
public class VpnService extends Service {
|
||||
|
||||
/**
|
||||
* The action must be matched by the intent filter of this service. It also
|
||||
* needs to require {@link android.Manifest.permission#BIND_VPN_SERVICE}
|
||||
* permission so that other applications cannot abuse it.
|
||||
*/
|
||||
public static final String SERVICE_INTERFACE = VpnConfig.SERVICE_INTERFACE;
|
||||
|
||||
/**
|
||||
* Key for boolean meta-data field indicating whether this VpnService supports always-on mode.
|
||||
*
|
||||
* <p>For a VPN app targeting {@link android.os.Build.VERSION_CODES#N API 24} or above, Android
|
||||
* provides users with the ability to set it as always-on, so that VPN connection is
|
||||
* persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device
|
||||
* owner and profile owner apps through
|
||||
* {@link DevicePolicyManager#setAlwaysOnVpnPackage}.
|
||||
*
|
||||
* <p>VPN apps not supporting this feature should opt out by adding this meta-data field to the
|
||||
* {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one
|
||||
* {@code VpnService} component defined in {@code AndroidManifest.xml}, opting out any one of
|
||||
* them will opt out the entire app. For example,
|
||||
* <pre> {@code
|
||||
* <service android:name=".ExampleVpnService"
|
||||
* android:permission="android.permission.BIND_VPN_SERVICE">
|
||||
* <intent-filter>
|
||||
* <action android:name="android.net.VpnService"/>
|
||||
* </intent-filter>
|
||||
* <meta-data android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
|
||||
* android:value=false/>
|
||||
* </service>
|
||||
* } </pre>
|
||||
*
|
||||
* <p>This meta-data field defaults to {@code true} if absent. It will only have effect on
|
||||
* {@link android.os.Build.VERSION_CODES#O_MR1} or higher.
|
||||
*/
|
||||
public static final String SERVICE_META_DATA_SUPPORTS_ALWAYS_ON =
|
||||
"android.net.VpnService.SUPPORTS_ALWAYS_ON";
|
||||
|
||||
/**
|
||||
* Use IConnectivityManager since those methods are hidden and not
|
||||
* available in ConnectivityManager.
|
||||
*/
|
||||
private static IConnectivityManager getService() {
|
||||
return IConnectivityManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to establish a VPN connection. This method returns {@code null}
|
||||
* if the VPN application is already prepared or if the user has previously
|
||||
* consented to the VPN application. Otherwise, it returns an
|
||||
* {@link Intent} to a system activity. The application should launch the
|
||||
* activity using {@link Activity#startActivityForResult} to get itself
|
||||
* prepared. The activity may pop up a dialog to require user action, and
|
||||
* the result will come back via its {@link Activity#onActivityResult}.
|
||||
* If the result is {@link Activity#RESULT_OK}, the application becomes
|
||||
* prepared and is granted to use other methods in this class.
|
||||
*
|
||||
* <p>Only one application can be granted at the same time. The right
|
||||
* is revoked when another application is granted. The application
|
||||
* losing the right will be notified via its {@link #onRevoke}. Unless
|
||||
* it becomes prepared again, subsequent calls to other methods in this
|
||||
* class will fail.
|
||||
*
|
||||
* <p>The user may disable the VPN at any time while it is activated, in
|
||||
* which case this method will return an intent the next time it is
|
||||
* executed to obtain the user's consent again.
|
||||
*
|
||||
* @see #onRevoke
|
||||
*/
|
||||
public static Intent prepare(Context context) {
|
||||
try {
|
||||
if (getService().prepareVpn(context.getPackageName(), null, context.getUserId())) {
|
||||
return null;
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// ignore
|
||||
}
|
||||
return VpnConfig.getIntentForConfirmation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of {@link #prepare(Context)} which does not require user consent.
|
||||
*
|
||||
* <p>Requires {@link android.Manifest.permission#CONTROL_VPN} and should generally not be
|
||||
* used. Only acceptable in situations where user consent has been obtained through other means.
|
||||
*
|
||||
* <p>Once this is run, future preparations may be done with the standard prepare method as this
|
||||
* will authorize the package to prepare the VPN without consent in the future.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.CONTROL_VPN)
|
||||
public static void prepareAndAuthorize(Context context) {
|
||||
IConnectivityManager cm = getService();
|
||||
String packageName = context.getPackageName();
|
||||
try {
|
||||
// Only prepare if we're not already prepared.
|
||||
int userId = context.getUserId();
|
||||
if (!cm.prepareVpn(packageName, null, userId)) {
|
||||
cm.prepareVpn(null, packageName, userId);
|
||||
}
|
||||
cm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE);
|
||||
} catch (RemoteException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protect a socket from VPN connections. After protecting, data sent
|
||||
* through this socket will go directly to the underlying network,
|
||||
* so its traffic will not be forwarded through the VPN.
|
||||
* This method is useful if some connections need to be kept
|
||||
* outside of VPN. For example, a VPN tunnel should protect itself if its
|
||||
* destination is covered by VPN routes. Otherwise its outgoing packets
|
||||
* will be sent back to the VPN interface and cause an infinite loop. This
|
||||
* method will fail if the application is not prepared or is revoked.
|
||||
*
|
||||
* <p class="note">The socket is NOT closed by this method.
|
||||
*
|
||||
* @return {@code true} on success.
|
||||
*/
|
||||
public boolean protect(int socket) {
|
||||
return NetworkUtils.protectFromVpn(socket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to protect a {@link Socket} from VPN connections.
|
||||
*
|
||||
* @return {@code true} on success.
|
||||
* @see #protect(int)
|
||||
*/
|
||||
public boolean protect(Socket socket) {
|
||||
return protect(socket.getFileDescriptor$().getInt$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to protect a {@link DatagramSocket} from VPN
|
||||
* connections.
|
||||
*
|
||||
* @return {@code true} on success.
|
||||
* @see #protect(int)
|
||||
*/
|
||||
public boolean protect(DatagramSocket socket) {
|
||||
return protect(socket.getFileDescriptor$().getInt$());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a network address to the VPN interface.
|
||||
*
|
||||
* Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the
|
||||
* address is already in use or cannot be assigned to the interface for any other reason.
|
||||
*
|
||||
* Adding an address implicitly allows traffic from that address family (i.e., IPv4 or IPv6) to
|
||||
* be routed over the VPN. @see Builder#allowFamily
|
||||
*
|
||||
* @throws IllegalArgumentException if the address is invalid.
|
||||
*
|
||||
* @param address The IP address (IPv4 or IPv6) to assign to the VPN interface.
|
||||
* @param prefixLength The prefix length of the address.
|
||||
*
|
||||
* @return {@code true} on success.
|
||||
* @see Builder#addAddress
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean addAddress(InetAddress address, int prefixLength) {
|
||||
check(address, prefixLength);
|
||||
try {
|
||||
return getService().addVpnAddress(address.getHostAddress(), prefixLength);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a network address from the VPN interface.
|
||||
*
|
||||
* Both IPv4 and IPv6 addresses are supported. The VPN must already be established. Fails if the
|
||||
* address is not assigned to the VPN interface, or if it is the only address assigned (thus
|
||||
* cannot be removed), or if the address cannot be removed for any other reason.
|
||||
*
|
||||
* After removing an address, if there are no addresses, routes or DNS servers of a particular
|
||||
* address family (i.e., IPv4 or IPv6) configured on the VPN, that <b>DOES NOT</b> block that
|
||||
* family from being routed. In other words, once an address family has been allowed, it stays
|
||||
* allowed for the rest of the VPN's session. @see Builder#allowFamily
|
||||
*
|
||||
* @throws IllegalArgumentException if the address is invalid.
|
||||
*
|
||||
* @param address The IP address (IPv4 or IPv6) to assign to the VPN interface.
|
||||
* @param prefixLength The prefix length of the address.
|
||||
*
|
||||
* @return {@code true} on success.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public boolean removeAddress(InetAddress address, int prefixLength) {
|
||||
check(address, prefixLength);
|
||||
try {
|
||||
return getService().removeVpnAddress(address.getHostAddress(), prefixLength);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underlying networks used by the VPN for its upstream connections.
|
||||
*
|
||||
* <p>Used by the system to know the actual networks that carry traffic for apps affected by
|
||||
* this VPN in order to present this information to the user (e.g., via status bar icons).
|
||||
*
|
||||
* <p>This method only needs to be called if the VPN has explicitly bound its underlying
|
||||
* communications channels — such as the socket(s) passed to {@link #protect(int)} —
|
||||
* to a {@code Network} using APIs such as {@link Network#bindSocket(Socket)} or
|
||||
* {@link Network#bindSocket(DatagramSocket)}. The VPN should call this method every time
|
||||
* the set of {@code Network}s it is using changes.
|
||||
*
|
||||
* <p>{@code networks} is one of the following:
|
||||
* <ul>
|
||||
* <li><strong>a non-empty array</strong>: an array of one or more {@link Network}s, in
|
||||
* decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular)
|
||||
* networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear
|
||||
* first in the array.</li>
|
||||
* <li><strong>an empty array</strong>: a zero-element array, meaning that the VPN has no
|
||||
* underlying network connection, and thus, app traffic will not be sent or received.</li>
|
||||
* <li><strong>null</strong>: (default) signifies that the VPN uses whatever is the system's
|
||||
* default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket}
|
||||
* APIs mentioned above to send traffic over specific channels.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>This call will succeed only if the VPN is currently established. For setting this value
|
||||
* when the VPN has not yet been established, see {@link Builder#setUnderlyingNetworks}.
|
||||
*
|
||||
* @param networks An array of networks the VPN uses to tunnel traffic to/from its servers.
|
||||
*
|
||||
* @return {@code true} on success.
|
||||
*/
|
||||
public boolean setUnderlyingNetworks(Network[] networks) {
|
||||
try {
|
||||
return getService().setUnderlyingNetworksForVpn(networks);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the service is running in always-on VPN mode. In this mode the system ensures
|
||||
* that the service is always running by restarting it when necessary, e.g. after reboot.
|
||||
*
|
||||
* @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
|
||||
*/
|
||||
public final boolean isAlwaysOn() {
|
||||
try {
|
||||
return getService().isCallerCurrentAlwaysOnVpnApp();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the service is running in always-on VPN lockdown mode. In this mode the
|
||||
* system ensures that the service is always running and that the apps aren't allowed to bypass
|
||||
* the VPN.
|
||||
*
|
||||
* @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
|
||||
*/
|
||||
public final boolean isLockdownEnabled() {
|
||||
try {
|
||||
return getService().isCallerCurrentAlwaysOnVpnLockdownApp();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the communication interface to the service. This method returns
|
||||
* {@code null} on {@link Intent}s other than {@link #SERVICE_INTERFACE}
|
||||
* action. Applications overriding this method must identify the intent
|
||||
* and return the corresponding interface accordingly.
|
||||
*
|
||||
* @see Service#onBind
|
||||
*/
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (intent != null && SERVICE_INTERFACE.equals(intent.getAction())) {
|
||||
return new Callback();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when the application is revoked. At this moment, the VPN
|
||||
* interface is already deactivated by the system. The application should
|
||||
* close the file descriptor and shut down gracefully. The default
|
||||
* implementation of this method is calling {@link Service#stopSelf()}.
|
||||
*
|
||||
* <p class="note">Calls to this method may not happen on the main thread
|
||||
* of the process.
|
||||
*
|
||||
* @see #prepare
|
||||
*/
|
||||
public void onRevoke() {
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use raw Binder instead of AIDL since now there is only one usage.
|
||||
*/
|
||||
private class Callback extends Binder {
|
||||
@Override
|
||||
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
|
||||
if (code == IBinder.LAST_CALL_TRANSACTION) {
|
||||
onRevoke();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Private method to validate address and prefixLength.
|
||||
*/
|
||||
private static void check(InetAddress address, int prefixLength) {
|
||||
if (address.isLoopbackAddress()) {
|
||||
throw new IllegalArgumentException("Bad address");
|
||||
}
|
||||
if (address instanceof Inet4Address) {
|
||||
if (prefixLength < 0 || prefixLength > 32) {
|
||||
throw new IllegalArgumentException("Bad prefixLength");
|
||||
}
|
||||
} else if (address instanceof Inet6Address) {
|
||||
if (prefixLength < 0 || prefixLength > 128) {
|
||||
throw new IllegalArgumentException("Bad prefixLength");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported family");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to create a VPN interface. This class should be always
|
||||
* used within the scope of the outer {@link VpnService}.
|
||||
*
|
||||
* @see VpnService
|
||||
*/
|
||||
public class Builder {
|
||||
|
||||
private final VpnConfig mConfig = new VpnConfig();
|
||||
@UnsupportedAppUsage
|
||||
private final List<LinkAddress> mAddresses = new ArrayList<LinkAddress>();
|
||||
@UnsupportedAppUsage
|
||||
private final List<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
|
||||
|
||||
public Builder() {
|
||||
mConfig.user = VpnService.this.getClass().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this session. It will be displayed in
|
||||
* system-managed dialogs and notifications. This is recommended
|
||||
* not required.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSession(@NonNull String session) {
|
||||
mConfig.session = session;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link PendingIntent} to an activity for users to
|
||||
* configure the VPN connection. If it is not set, the button
|
||||
* to configure will not be shown in system-managed dialogs.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setConfigureIntent(@NonNull PendingIntent intent) {
|
||||
mConfig.configureIntent = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum transmission unit (MTU) of the VPN interface. If
|
||||
* it is not set, the default value in the operating system will be
|
||||
* used.
|
||||
*
|
||||
* @throws IllegalArgumentException if the value is not positive.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setMtu(int mtu) {
|
||||
if (mtu <= 0) {
|
||||
throw new IllegalArgumentException("Bad mtu");
|
||||
}
|
||||
mConfig.mtu = mtu;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an HTTP proxy for the VPN network. This proxy is only a recommendation
|
||||
* and it is possible that some apps will ignore it.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setHttpProxy(@NonNull ProxyInfo proxyInfo) {
|
||||
mConfig.proxyInfo = proxyInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a network address to the VPN interface. Both IPv4 and IPv6
|
||||
* addresses are supported. At least one address must be set before
|
||||
* calling {@link #establish}.
|
||||
*
|
||||
* Adding an address implicitly allows traffic from that address family
|
||||
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
|
||||
*
|
||||
* @throws IllegalArgumentException if the address is invalid.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addAddress(@NonNull InetAddress address, int prefixLength) {
|
||||
check(address, prefixLength);
|
||||
|
||||
if (address.isAnyLocalAddress()) {
|
||||
throw new IllegalArgumentException("Bad address");
|
||||
}
|
||||
mAddresses.add(new LinkAddress(address, prefixLength));
|
||||
mConfig.updateAllowedFamilies(address);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a network address to the VPN interface
|
||||
* using a numeric address string. See {@link InetAddress} for the
|
||||
* definitions of numeric address formats.
|
||||
*
|
||||
* Adding an address implicitly allows traffic from that address family
|
||||
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
|
||||
*
|
||||
* @throws IllegalArgumentException if the address is invalid.
|
||||
* @see #addAddress(InetAddress, int)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addAddress(@NonNull String address, int prefixLength) {
|
||||
return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a network route to the VPN interface. Both IPv4 and IPv6
|
||||
* routes are supported.
|
||||
*
|
||||
* Adding a route implicitly allows traffic from that address family
|
||||
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
|
||||
*
|
||||
* @throws IllegalArgumentException if the route is invalid.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addRoute(@NonNull InetAddress address, int prefixLength) {
|
||||
check(address, prefixLength);
|
||||
|
||||
int offset = prefixLength / 8;
|
||||
byte[] bytes = address.getAddress();
|
||||
if (offset < bytes.length) {
|
||||
for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) {
|
||||
if (bytes[offset] != 0) {
|
||||
throw new IllegalArgumentException("Bad address");
|
||||
}
|
||||
}
|
||||
}
|
||||
mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null));
|
||||
mConfig.updateAllowedFamilies(address);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a network route to the VPN interface
|
||||
* using a numeric address string. See {@link InetAddress} for the
|
||||
* definitions of numeric address formats.
|
||||
*
|
||||
* Adding a route implicitly allows traffic from that address family
|
||||
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
|
||||
*
|
||||
* @throws IllegalArgumentException if the route is invalid.
|
||||
* @see #addRoute(InetAddress, int)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addRoute(@NonNull String address, int prefixLength) {
|
||||
return addRoute(InetAddress.parseNumericAddress(address), prefixLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a DNS server to the VPN connection. Both IPv4 and IPv6
|
||||
* addresses are supported. If none is set, the DNS servers of
|
||||
* the default network will be used.
|
||||
*
|
||||
* Adding a server implicitly allows traffic from that address family
|
||||
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
|
||||
*
|
||||
* @throws IllegalArgumentException if the address is invalid.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addDnsServer(@NonNull InetAddress address) {
|
||||
if (address.isLoopbackAddress() || address.isAnyLocalAddress()) {
|
||||
throw new IllegalArgumentException("Bad address");
|
||||
}
|
||||
if (mConfig.dnsServers == null) {
|
||||
mConfig.dnsServers = new ArrayList<String>();
|
||||
}
|
||||
mConfig.dnsServers.add(address.getHostAddress());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a DNS server to the VPN connection
|
||||
* using a numeric address string. See {@link InetAddress} for the
|
||||
* definitions of numeric address formats.
|
||||
*
|
||||
* Adding a server implicitly allows traffic from that address family
|
||||
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
|
||||
*
|
||||
* @throws IllegalArgumentException if the address is invalid.
|
||||
* @see #addDnsServer(InetAddress)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addDnsServer(@NonNull String address) {
|
||||
return addDnsServer(InetAddress.parseNumericAddress(address));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a search domain to the DNS resolver.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addSearchDomain(@NonNull String domain) {
|
||||
if (mConfig.searchDomains == null) {
|
||||
mConfig.searchDomains = new ArrayList<String>();
|
||||
}
|
||||
mConfig.searchDomains.add(domain);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows traffic from the specified address family.
|
||||
*
|
||||
* By default, if no address, route or DNS server of a specific family (IPv4 or IPv6) is
|
||||
* added to this VPN, then all outgoing traffic of that family is blocked. If any address,
|
||||
* route or DNS server is added, that family is allowed.
|
||||
*
|
||||
* This method allows an address family to be unblocked even without adding an address,
|
||||
* route or DNS server of that family. Traffic of that family will then typically
|
||||
* fall-through to the underlying network if it's supported.
|
||||
*
|
||||
* {@code family} must be either {@code AF_INET} (for IPv4) or {@code AF_INET6} (for IPv6).
|
||||
* {@link IllegalArgumentException} is thrown if it's neither.
|
||||
*
|
||||
* @param family The address family ({@code AF_INET} or {@code AF_INET6}) to allow.
|
||||
*
|
||||
* @return this {@link Builder} object to facilitate chaining of method calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder allowFamily(int family) {
|
||||
if (family == AF_INET) {
|
||||
mConfig.allowIPv4 = true;
|
||||
} else if (family == AF_INET6) {
|
||||
mConfig.allowIPv6 = true;
|
||||
} else {
|
||||
throw new IllegalArgumentException(family + " is neither " + AF_INET + " nor " +
|
||||
AF_INET6);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void verifyApp(String packageName) throws PackageManager.NameNotFoundException {
|
||||
IPackageManager pm = IPackageManager.Stub.asInterface(
|
||||
ServiceManager.getService("package"));
|
||||
try {
|
||||
pm.getApplicationInfo(packageName, 0, UserHandle.getCallingUserId());
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an application that's allowed to access the VPN connection.
|
||||
*
|
||||
* If this method is called at least once, only applications added through this method (and
|
||||
* no others) are allowed access. Else (if this method is never called), all applications
|
||||
* are allowed by default. If some applications are added, other, un-added applications
|
||||
* will use networking as if the VPN wasn't running.
|
||||
*
|
||||
* A {@link Builder} may have only a set of allowed applications OR a set of disallowed
|
||||
* ones, but not both. Calling this method after {@link #addDisallowedApplication} has
|
||||
* already been called, or vice versa, will throw an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* {@code packageName} must be the canonical name of a currently installed application.
|
||||
* {@link PackageManager.NameNotFoundException} is thrown if there's no such application.
|
||||
*
|
||||
* @throws PackageManager.NameNotFoundException If the application isn't installed.
|
||||
*
|
||||
* @param packageName The full name (e.g.: "com.google.apps.contacts") of an application.
|
||||
*
|
||||
* @return this {@link Builder} object to facilitate chaining method calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addAllowedApplication(@NonNull String packageName)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
if (mConfig.disallowedApplications != null) {
|
||||
throw new UnsupportedOperationException("addDisallowedApplication already called");
|
||||
}
|
||||
verifyApp(packageName);
|
||||
if (mConfig.allowedApplications == null) {
|
||||
mConfig.allowedApplications = new ArrayList<String>();
|
||||
}
|
||||
mConfig.allowedApplications.add(packageName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an application that's denied access to the VPN connection.
|
||||
*
|
||||
* By default, all applications are allowed access, except for those denied through this
|
||||
* method. Denied applications will use networking as if the VPN wasn't running.
|
||||
*
|
||||
* A {@link Builder} may have only a set of allowed applications OR a set of disallowed
|
||||
* ones, but not both. Calling this method after {@link #addAllowedApplication} has already
|
||||
* been called, or vice versa, will throw an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* {@code packageName} must be the canonical name of a currently installed application.
|
||||
* {@link PackageManager.NameNotFoundException} is thrown if there's no such application.
|
||||
*
|
||||
* @throws PackageManager.NameNotFoundException If the application isn't installed.
|
||||
*
|
||||
* @param packageName The full name (e.g.: "com.google.apps.contacts") of an application.
|
||||
*
|
||||
* @return this {@link Builder} object to facilitate chaining method calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder addDisallowedApplication(@NonNull String packageName)
|
||||
throws PackageManager.NameNotFoundException {
|
||||
if (mConfig.allowedApplications != null) {
|
||||
throw new UnsupportedOperationException("addAllowedApplication already called");
|
||||
}
|
||||
verifyApp(packageName);
|
||||
if (mConfig.disallowedApplications == null) {
|
||||
mConfig.disallowedApplications = new ArrayList<String>();
|
||||
}
|
||||
mConfig.disallowedApplications.add(packageName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows all apps to bypass this VPN connection.
|
||||
*
|
||||
* By default, all traffic from apps is forwarded through the VPN interface and it is not
|
||||
* possible for apps to side-step the VPN. If this method is called, apps may use methods
|
||||
* such as {@link ConnectivityManager#bindProcessToNetwork} to instead send/receive
|
||||
* directly over the underlying network or any other network they have permissions for.
|
||||
*
|
||||
* @return this {@link Builder} object to facilitate chaining of method calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder allowBypass() {
|
||||
mConfig.allowBypass = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the VPN interface's file descriptor to be in blocking/non-blocking mode.
|
||||
*
|
||||
* By default, the file descriptor returned by {@link #establish} is non-blocking.
|
||||
*
|
||||
* @param blocking True to put the descriptor into blocking mode; false for non-blocking.
|
||||
*
|
||||
* @return this {@link Builder} object to facilitate chaining method calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setBlocking(boolean blocking) {
|
||||
mConfig.blocking = blocking;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underlying networks used by the VPN for its upstream connections.
|
||||
*
|
||||
* @see VpnService#setUnderlyingNetworks
|
||||
*
|
||||
* @param networks An array of networks the VPN uses to tunnel traffic to/from its servers.
|
||||
*
|
||||
* @return this {@link Builder} object to facilitate chaining method calls.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setUnderlyingNetworks(@Nullable Network[] networks) {
|
||||
mConfig.underlyingNetworks = networks != null ? networks.clone() : null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the VPN network as metered. A VPN network is classified as metered when the user is
|
||||
* sensitive to heavy data usage due to monetary costs and/or data limitations. In such
|
||||
* cases, you should set this to {@code true} so that apps on the system can avoid doing
|
||||
* large data transfers. Otherwise, set this to {@code false}. Doing so would cause VPN
|
||||
* network to inherit its meteredness from its underlying networks.
|
||||
*
|
||||
* <p>VPN apps targeting {@link android.os.Build.VERSION_CODES#Q} or above will be
|
||||
* considered metered by default.
|
||||
*
|
||||
* @param isMetered {@code true} if VPN network should be treated as metered regardless of
|
||||
* underlying network meteredness
|
||||
* @return this {@link Builder} object to facilitate chaining method calls
|
||||
* @see #setUnderlyingNetworks(Network[])
|
||||
* @see ConnectivityManager#isActiveNetworkMetered()
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setMetered(boolean isMetered) {
|
||||
mConfig.isMetered = isMetered;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a VPN interface using the parameters supplied to this
|
||||
* builder. The interface works on IP packets, and a file descriptor
|
||||
* is returned for the application to access them. Each read
|
||||
* retrieves an outgoing packet which was routed to the interface.
|
||||
* Each write injects an incoming packet just like it was received
|
||||
* from the interface. The file descriptor is put into non-blocking
|
||||
* mode by default to avoid blocking Java threads. To use the file
|
||||
* descriptor completely in native space, see
|
||||
* {@link ParcelFileDescriptor#detachFd()}. The application MUST
|
||||
* close the file descriptor when the VPN connection is terminated.
|
||||
* The VPN interface will be removed and the network will be
|
||||
* restored by the system automatically.
|
||||
*
|
||||
* <p>To avoid conflicts, there can be only one active VPN interface
|
||||
* at the same time. Usually network parameters are never changed
|
||||
* during the lifetime of a VPN connection. It is also common for an
|
||||
* application to create a new file descriptor after closing the
|
||||
* previous one. However, it is rare but not impossible to have two
|
||||
* interfaces while performing a seamless handover. In this case, the
|
||||
* old interface will be deactivated when the new one is created
|
||||
* successfully. Both file descriptors are valid but now outgoing
|
||||
* packets will be routed to the new interface. Therefore, after
|
||||
* draining the old file descriptor, the application MUST close it
|
||||
* and start using the new file descriptor. If the new interface
|
||||
* cannot be created, the existing interface and its file descriptor
|
||||
* remain untouched.
|
||||
*
|
||||
* <p>An exception will be thrown if the interface cannot be created
|
||||
* for any reason. However, this method returns {@code null} if the
|
||||
* application is not prepared or is revoked. This helps solve
|
||||
* possible race conditions between other VPN applications.
|
||||
*
|
||||
* @return {@link ParcelFileDescriptor} of the VPN interface, or
|
||||
* {@code null} if the application is not prepared.
|
||||
* @throws IllegalArgumentException if a parameter is not accepted
|
||||
* by the operating system.
|
||||
* @throws IllegalStateException if a parameter cannot be applied
|
||||
* by the operating system.
|
||||
* @throws SecurityException if the service is not properly declared
|
||||
* in {@code AndroidManifest.xml}.
|
||||
* @see VpnService
|
||||
*/
|
||||
@Nullable
|
||||
public ParcelFileDescriptor establish() {
|
||||
mConfig.addresses = mAddresses;
|
||||
mConfig.routes = mRoutes;
|
||||
|
||||
try {
|
||||
return getService().establishVpn(mConfig);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
framework/src/android/net/apf/ApfCapabilities.aidl
Normal file
20
framework/src/android/net/apf/ApfCapabilities.aidl
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
**
|
||||
** Copyright (C) 2019 The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.apf;
|
||||
|
||||
@JavaOnlyStableParcelable parcelable ApfCapabilities;
|
||||
133
framework/src/android/net/apf/ApfCapabilities.java
Normal file
133
framework/src/android/net/apf/ApfCapabilities.java
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.apf;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
/**
|
||||
* APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible
|
||||
* way to drop unwanted network packets to save power.
|
||||
*
|
||||
* See documentation at hardware/google/apf/apf.h
|
||||
*
|
||||
* This class is immutable.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class ApfCapabilities implements Parcelable {
|
||||
/**
|
||||
* Version of APF instruction set supported for packet filtering. 0 indicates no support for
|
||||
* packet filtering using APF programs.
|
||||
*/
|
||||
public final int apfVersionSupported;
|
||||
|
||||
/**
|
||||
* Maximum size of APF program allowed.
|
||||
*/
|
||||
public final int maximumApfProgramSize;
|
||||
|
||||
/**
|
||||
* Format of packets passed to APF filter. Should be one of ARPHRD_*
|
||||
*/
|
||||
public final int apfPacketFormat;
|
||||
|
||||
public ApfCapabilities(
|
||||
int apfVersionSupported, int maximumApfProgramSize, int apfPacketFormat) {
|
||||
this.apfVersionSupported = apfVersionSupported;
|
||||
this.maximumApfProgramSize = maximumApfProgramSize;
|
||||
this.apfPacketFormat = apfPacketFormat;
|
||||
}
|
||||
|
||||
private ApfCapabilities(Parcel in) {
|
||||
apfVersionSupported = in.readInt();
|
||||
maximumApfProgramSize = in.readInt();
|
||||
apfPacketFormat = in.readInt();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(apfVersionSupported);
|
||||
dest.writeInt(maximumApfProgramSize);
|
||||
dest.writeInt(apfPacketFormat);
|
||||
}
|
||||
|
||||
public static final Creator<ApfCapabilities> CREATOR = new Creator<ApfCapabilities>() {
|
||||
@Override
|
||||
public ApfCapabilities createFromParcel(Parcel in) {
|
||||
return new ApfCapabilities(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApfCapabilities[] newArray(int size) {
|
||||
return new ApfCapabilities[size];
|
||||
}
|
||||
};
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
|
||||
apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (!(obj instanceof ApfCapabilities)) return false;
|
||||
final ApfCapabilities other = (ApfCapabilities) obj;
|
||||
return apfVersionSupported == other.apfVersionSupported
|
||||
&& maximumApfProgramSize == other.maximumApfProgramSize
|
||||
&& apfPacketFormat == other.apfPacketFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the APF interpreter advertises support for the data buffer access opcodes
|
||||
* LDDW (LoaD Data Word) and STDW (STore Data Word). Full LDDW (LoaD Data Word) and
|
||||
* STDW (STore Data Word) support is present from APFv4 on.
|
||||
*
|
||||
* @return {@code true} if the IWifiStaIface#readApfPacketFilterData is supported.
|
||||
*/
|
||||
public boolean hasDataAccess() {
|
||||
return apfVersionSupported >= 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
|
||||
*/
|
||||
public static boolean getApfDrop8023Frames() {
|
||||
return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped.
|
||||
*/
|
||||
public static @NonNull int[] getApfEtherTypeBlackList() {
|
||||
return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList);
|
||||
}
|
||||
}
|
||||
379
framework/src/android/net/util/DnsUtils.java
Normal file
379
framework/src/android/net/util/DnsUtils.java
Normal file
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.util;
|
||||
|
||||
import static android.system.OsConstants.AF_INET;
|
||||
import static android.system.OsConstants.AF_INET6;
|
||||
import static android.system.OsConstants.IPPROTO_UDP;
|
||||
import static android.system.OsConstants.SOCK_DGRAM;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.InetAddresses;
|
||||
import android.net.Network;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.BitUtils;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class DnsUtils {
|
||||
private static final String TAG = "DnsUtils";
|
||||
private static final int CHAR_BIT = 8;
|
||||
public static final int IPV6_ADDR_SCOPE_NODELOCAL = 0x01;
|
||||
public static final int IPV6_ADDR_SCOPE_LINKLOCAL = 0x02;
|
||||
public static final int IPV6_ADDR_SCOPE_SITELOCAL = 0x05;
|
||||
public static final int IPV6_ADDR_SCOPE_GLOBAL = 0x0e;
|
||||
private static final Comparator<SortableAddress> sRfc6724Comparator = new Rfc6724Comparator();
|
||||
|
||||
/**
|
||||
* Comparator to sort SortableAddress in Rfc6724 style.
|
||||
*/
|
||||
public static class Rfc6724Comparator implements Comparator<SortableAddress> {
|
||||
// This function matches the behaviour of _rfc6724_compare in the native resolver.
|
||||
@Override
|
||||
public int compare(SortableAddress span1, SortableAddress span2) {
|
||||
// Rule 1: Avoid unusable destinations.
|
||||
if (span1.hasSrcAddr != span2.hasSrcAddr) {
|
||||
return span2.hasSrcAddr - span1.hasSrcAddr;
|
||||
}
|
||||
|
||||
// Rule 2: Prefer matching scope.
|
||||
if (span1.scopeMatch != span2.scopeMatch) {
|
||||
return span2.scopeMatch - span1.scopeMatch;
|
||||
}
|
||||
|
||||
// TODO: Implement rule 3: Avoid deprecated addresses.
|
||||
// TODO: Implement rule 4: Prefer home addresses.
|
||||
|
||||
// Rule 5: Prefer matching label.
|
||||
if (span1.labelMatch != span2.labelMatch) {
|
||||
return span2.labelMatch - span1.labelMatch;
|
||||
}
|
||||
|
||||
// Rule 6: Prefer higher precedence.
|
||||
if (span1.precedence != span2.precedence) {
|
||||
return span2.precedence - span1.precedence;
|
||||
}
|
||||
|
||||
// TODO: Implement rule 7: Prefer native transport.
|
||||
|
||||
// Rule 8: Prefer smaller scope.
|
||||
if (span1.scope != span2.scope) {
|
||||
return span1.scope - span2.scope;
|
||||
}
|
||||
|
||||
// Rule 9: Use longest matching prefix. IPv6 only.
|
||||
if (span1.prefixMatchLen != span2.prefixMatchLen) {
|
||||
return span2.prefixMatchLen - span1.prefixMatchLen;
|
||||
}
|
||||
|
||||
// Rule 10: Leave the order unchanged. Collections.sort is a stable sort.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used to sort with RFC 6724
|
||||
*/
|
||||
public static class SortableAddress {
|
||||
public final int label;
|
||||
public final int labelMatch;
|
||||
public final int scope;
|
||||
public final int scopeMatch;
|
||||
public final int precedence;
|
||||
public final int prefixMatchLen;
|
||||
public final int hasSrcAddr;
|
||||
public final InetAddress address;
|
||||
|
||||
public SortableAddress(@NonNull InetAddress addr, @Nullable InetAddress srcAddr) {
|
||||
address = addr;
|
||||
hasSrcAddr = (srcAddr != null) ? 1 : 0;
|
||||
label = findLabel(addr);
|
||||
scope = findScope(addr);
|
||||
precedence = findPrecedence(addr);
|
||||
labelMatch = ((srcAddr != null) && (label == findLabel(srcAddr))) ? 1 : 0;
|
||||
scopeMatch = ((srcAddr != null) && (scope == findScope(srcAddr))) ? 1 : 0;
|
||||
if (isIpv6Address(addr) && isIpv6Address(srcAddr)) {
|
||||
prefixMatchLen = compareIpv6PrefixMatchLen(srcAddr, addr);
|
||||
} else {
|
||||
prefixMatchLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the given address list in RFC6724 order.
|
||||
* Will leave the list unchanged if an error occurs.
|
||||
*
|
||||
* This function matches the behaviour of _rfc6724_sort in the native resolver.
|
||||
*/
|
||||
public static @NonNull List<InetAddress> rfc6724Sort(@Nullable Network network,
|
||||
@NonNull List<InetAddress> answers) {
|
||||
final ArrayList<SortableAddress> sortableAnswerList = new ArrayList<>();
|
||||
for (InetAddress addr : answers) {
|
||||
sortableAnswerList.add(new SortableAddress(addr, findSrcAddress(network, addr)));
|
||||
}
|
||||
|
||||
Collections.sort(sortableAnswerList, sRfc6724Comparator);
|
||||
|
||||
final List<InetAddress> sortedAnswers = new ArrayList<>();
|
||||
for (SortableAddress ans : sortableAnswerList) {
|
||||
sortedAnswers.add(ans.address);
|
||||
}
|
||||
|
||||
return sortedAnswers;
|
||||
}
|
||||
|
||||
private static @Nullable InetAddress findSrcAddress(@Nullable Network network,
|
||||
@NonNull InetAddress addr) {
|
||||
final int domain;
|
||||
if (isIpv4Address(addr)) {
|
||||
domain = AF_INET;
|
||||
} else if (isIpv6Address(addr)) {
|
||||
domain = AF_INET6;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
final FileDescriptor socket;
|
||||
try {
|
||||
socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP);
|
||||
} catch (ErrnoException e) {
|
||||
Log.e(TAG, "findSrcAddress:" + e.toString());
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
if (network != null) network.bindSocket(socket);
|
||||
Os.connect(socket, new InetSocketAddress(addr, 0));
|
||||
return ((InetSocketAddress) Os.getsockname(socket)).getAddress();
|
||||
} catch (IOException | ErrnoException e) {
|
||||
return null;
|
||||
} finally {
|
||||
IoUtils.closeQuietly(socket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the label for a given IPv4/IPv6 address.
|
||||
* RFC 6724, section 2.1.
|
||||
*
|
||||
* Note that Java will return an IPv4-mapped address as an IPv4 address.
|
||||
*/
|
||||
private static int findLabel(@NonNull InetAddress addr) {
|
||||
if (isIpv4Address(addr)) {
|
||||
return 4;
|
||||
} else if (isIpv6Address(addr)) {
|
||||
if (addr.isLoopbackAddress()) {
|
||||
return 0;
|
||||
} else if (isIpv6Address6To4(addr)) {
|
||||
return 2;
|
||||
} else if (isIpv6AddressTeredo(addr)) {
|
||||
return 5;
|
||||
} else if (isIpv6AddressULA(addr)) {
|
||||
return 13;
|
||||
} else if (((Inet6Address) addr).isIPv4CompatibleAddress()) {
|
||||
return 3;
|
||||
} else if (addr.isSiteLocalAddress()) {
|
||||
return 11;
|
||||
} else if (isIpv6Address6Bone(addr)) {
|
||||
return 12;
|
||||
} else {
|
||||
// All other IPv6 addresses, including global unicast addresses.
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
// This should never happen.
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isIpv6Address(@Nullable InetAddress addr) {
|
||||
return addr instanceof Inet6Address;
|
||||
}
|
||||
|
||||
private static boolean isIpv4Address(@Nullable InetAddress addr) {
|
||||
return addr instanceof Inet4Address;
|
||||
}
|
||||
|
||||
private static boolean isIpv6Address6To4(@NonNull InetAddress addr) {
|
||||
if (!isIpv6Address(addr)) return false;
|
||||
final byte[] byteAddr = addr.getAddress();
|
||||
return byteAddr[0] == 0x20 && byteAddr[1] == 0x02;
|
||||
}
|
||||
|
||||
private static boolean isIpv6AddressTeredo(@NonNull InetAddress addr) {
|
||||
if (!isIpv6Address(addr)) return false;
|
||||
final byte[] byteAddr = addr.getAddress();
|
||||
return byteAddr[0] == 0x20 && byteAddr[1] == 0x01 && byteAddr[2] == 0x00
|
||||
&& byteAddr[3] == 0x00;
|
||||
}
|
||||
|
||||
private static boolean isIpv6AddressULA(@NonNull InetAddress addr) {
|
||||
return isIpv6Address(addr) && (addr.getAddress()[0] & 0xfe) == 0xfc;
|
||||
}
|
||||
|
||||
private static boolean isIpv6Address6Bone(@NonNull InetAddress addr) {
|
||||
if (!isIpv6Address(addr)) return false;
|
||||
final byte[] byteAddr = addr.getAddress();
|
||||
return byteAddr[0] == 0x3f && byteAddr[1] == (byte) 0xfe;
|
||||
}
|
||||
|
||||
private static int getIpv6MulticastScope(@NonNull InetAddress addr) {
|
||||
return !isIpv6Address(addr) ? 0 : (addr.getAddress()[1] & 0x0f);
|
||||
}
|
||||
|
||||
private static int findScope(@NonNull InetAddress addr) {
|
||||
if (isIpv6Address(addr)) {
|
||||
if (addr.isMulticastAddress()) {
|
||||
return getIpv6MulticastScope(addr);
|
||||
} else if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
|
||||
/**
|
||||
* RFC 4291 section 2.5.3 says loopback is to be treated as having
|
||||
* link-local scope.
|
||||
*/
|
||||
return IPV6_ADDR_SCOPE_LINKLOCAL;
|
||||
} else if (addr.isSiteLocalAddress()) {
|
||||
return IPV6_ADDR_SCOPE_SITELOCAL;
|
||||
} else {
|
||||
return IPV6_ADDR_SCOPE_GLOBAL;
|
||||
}
|
||||
} else if (isIpv4Address(addr)) {
|
||||
if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) {
|
||||
return IPV6_ADDR_SCOPE_LINKLOCAL;
|
||||
} else {
|
||||
/**
|
||||
* RFC 6724 section 3.2. Other IPv4 addresses, including private addresses
|
||||
* and shared addresses (100.64.0.0/10), are assigned global scope.
|
||||
*/
|
||||
return IPV6_ADDR_SCOPE_GLOBAL;
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* This should never happen.
|
||||
* Return a scope with low priority as a last resort.
|
||||
*/
|
||||
return IPV6_ADDR_SCOPE_NODELOCAL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the precedence for a given IPv4/IPv6 address.
|
||||
* RFC 6724, section 2.1.
|
||||
*
|
||||
* Note that Java will return an IPv4-mapped address as an IPv4 address.
|
||||
*/
|
||||
private static int findPrecedence(@NonNull InetAddress addr) {
|
||||
if (isIpv4Address(addr)) {
|
||||
return 35;
|
||||
} else if (isIpv6Address(addr)) {
|
||||
if (addr.isLoopbackAddress()) {
|
||||
return 50;
|
||||
} else if (isIpv6Address6To4(addr)) {
|
||||
return 30;
|
||||
} else if (isIpv6AddressTeredo(addr)) {
|
||||
return 5;
|
||||
} else if (isIpv6AddressULA(addr)) {
|
||||
return 3;
|
||||
} else if (((Inet6Address) addr).isIPv4CompatibleAddress() || addr.isSiteLocalAddress()
|
||||
|| isIpv6Address6Bone(addr)) {
|
||||
return 1;
|
||||
} else {
|
||||
// All other IPv6 addresses, including global unicast addresses.
|
||||
return 40;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find number of matching initial bits between the two addresses.
|
||||
*/
|
||||
private static int compareIpv6PrefixMatchLen(@NonNull InetAddress srcAddr,
|
||||
@NonNull InetAddress dstAddr) {
|
||||
final byte[] srcByte = srcAddr.getAddress();
|
||||
final byte[] dstByte = dstAddr.getAddress();
|
||||
|
||||
// This should never happen.
|
||||
if (srcByte.length != dstByte.length) return 0;
|
||||
|
||||
for (int i = 0; i < dstByte.length; ++i) {
|
||||
if (srcByte[i] == dstByte[i]) {
|
||||
continue;
|
||||
}
|
||||
int x = BitUtils.uint8(srcByte[i]) ^ BitUtils.uint8(dstByte[i]);
|
||||
return i * CHAR_BIT + (Integer.numberOfLeadingZeros(x) - 24); // Java ints are 32 bits
|
||||
}
|
||||
return dstByte.length * CHAR_BIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given network has Ipv4 capability
|
||||
* This function matches the behaviour of have_ipv4 in the native resolver.
|
||||
*/
|
||||
public static boolean haveIpv4(@Nullable Network network) {
|
||||
final SocketAddress addrIpv4 =
|
||||
new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0);
|
||||
return checkConnectivity(network, AF_INET, addrIpv4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given network has Ipv6 capability
|
||||
* This function matches the behaviour of have_ipv6 in the native resolver.
|
||||
*/
|
||||
public static boolean haveIpv6(@Nullable Network network) {
|
||||
final SocketAddress addrIpv6 =
|
||||
new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0);
|
||||
return checkConnectivity(network, AF_INET6, addrIpv6);
|
||||
}
|
||||
|
||||
private static boolean checkConnectivity(@Nullable Network network,
|
||||
int domain, @NonNull SocketAddress addr) {
|
||||
final FileDescriptor socket;
|
||||
try {
|
||||
socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP);
|
||||
} catch (ErrnoException e) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (network != null) network.bindSocket(socket);
|
||||
Os.connect(socket, addr);
|
||||
} catch (IOException | ErrnoException e) {
|
||||
return false;
|
||||
} finally {
|
||||
IoUtils.closeQuietly(socket);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
115
framework/src/android/net/util/KeepaliveUtils.java
Normal file
115
framework/src/android/net/util/KeepaliveUtils.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.util;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AndroidRuntimeException;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
/**
|
||||
* Collection of utilities for socket keepalive offload.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class KeepaliveUtils {
|
||||
|
||||
public static final String TAG = "KeepaliveUtils";
|
||||
|
||||
public static class KeepaliveDeviceConfigurationException extends AndroidRuntimeException {
|
||||
public KeepaliveDeviceConfigurationException(final String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read supported keepalive count for each transport type from overlay resource. This should be
|
||||
* used to create a local variable store of resource customization, and use it as the input for
|
||||
* {@link getSupportedKeepalivesForNetworkCapabilities}.
|
||||
*
|
||||
* @param context The context to read resource from.
|
||||
* @return An array of supported keepalive count for each transport type.
|
||||
*/
|
||||
@NonNull
|
||||
public static int[] getSupportedKeepalives(@NonNull Context context) {
|
||||
String[] res = null;
|
||||
try {
|
||||
res = context.getResources().getStringArray(
|
||||
R.array.config_networkSupportedKeepaliveCount);
|
||||
} catch (Resources.NotFoundException unused) {
|
||||
}
|
||||
if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource");
|
||||
|
||||
final int[] ret = new int[NetworkCapabilities.MAX_TRANSPORT + 1];
|
||||
for (final String row : res) {
|
||||
if (TextUtils.isEmpty(row)) {
|
||||
throw new KeepaliveDeviceConfigurationException("Empty string");
|
||||
}
|
||||
final String[] arr = row.split(",");
|
||||
if (arr.length != 2) {
|
||||
throw new KeepaliveDeviceConfigurationException("Invalid parameter length");
|
||||
}
|
||||
|
||||
int transport;
|
||||
int supported;
|
||||
try {
|
||||
transport = Integer.parseInt(arr[0]);
|
||||
supported = Integer.parseInt(arr[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new KeepaliveDeviceConfigurationException("Invalid number format");
|
||||
}
|
||||
|
||||
if (!NetworkCapabilities.isValidTransport(transport)) {
|
||||
throw new KeepaliveDeviceConfigurationException("Invalid transport " + transport);
|
||||
}
|
||||
|
||||
if (supported < 0) {
|
||||
throw new KeepaliveDeviceConfigurationException(
|
||||
"Invalid supported count " + supported + " for "
|
||||
+ NetworkCapabilities.transportNameOf(transport));
|
||||
}
|
||||
ret[transport] = supported;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get supported keepalive count for the given {@link NetworkCapabilities}.
|
||||
*
|
||||
* @param supportedKeepalives An array of supported keepalive count for each transport type.
|
||||
* @param nc The {@link NetworkCapabilities} of the network the socket keepalive is on.
|
||||
*
|
||||
* @return Supported keepalive count for the given {@link NetworkCapabilities}.
|
||||
*/
|
||||
public static int getSupportedKeepalivesForNetworkCapabilities(
|
||||
@NonNull int[] supportedKeepalives, @NonNull NetworkCapabilities nc) {
|
||||
final int[] transports = nc.getTransportTypes();
|
||||
if (transports.length == 0) return 0;
|
||||
int supportedCount = supportedKeepalives[transports[0]];
|
||||
// Iterate through transports and return minimum supported value.
|
||||
for (final int transport : transports) {
|
||||
if (supportedCount > supportedKeepalives[transport]) {
|
||||
supportedCount = supportedKeepalives[transport];
|
||||
}
|
||||
}
|
||||
return supportedCount;
|
||||
}
|
||||
}
|
||||
217
framework/src/android/net/util/MultinetworkPolicyTracker.java
Normal file
217
framework/src/android/net/util/MultinetworkPolicyTracker.java
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.util;
|
||||
|
||||
import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
|
||||
import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class to encapsulate management of the "Smart Networking" capability of
|
||||
* avoiding bad Wi-Fi when, for example upstream connectivity is lost or
|
||||
* certain critical link failures occur.
|
||||
*
|
||||
* This enables the device to switch to another form of connectivity, like
|
||||
* mobile, if it's available and working.
|
||||
*
|
||||
* The Runnable |avoidBadWifiCallback|, if given, is posted to the supplied
|
||||
* Handler' whenever the computed "avoid bad wifi" value changes.
|
||||
*
|
||||
* Disabling this reverts the device to a level of networking sophistication
|
||||
* circa 2012-13 by disabling disparate code paths each of which contribute to
|
||||
* maintaining continuous, working Internet connectivity.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class MultinetworkPolicyTracker {
|
||||
private static String TAG = MultinetworkPolicyTracker.class.getSimpleName();
|
||||
|
||||
private final Context mContext;
|
||||
private final Handler mHandler;
|
||||
private final Runnable mAvoidBadWifiCallback;
|
||||
private final List<Uri> mSettingsUris;
|
||||
private final ContentResolver mResolver;
|
||||
private final SettingObserver mSettingObserver;
|
||||
private final BroadcastReceiver mBroadcastReceiver;
|
||||
|
||||
private volatile boolean mAvoidBadWifi = true;
|
||||
private volatile int mMeteredMultipathPreference;
|
||||
private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
|
||||
public MultinetworkPolicyTracker(Context ctx, Handler handler) {
|
||||
this(ctx, handler, null);
|
||||
}
|
||||
|
||||
public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
|
||||
mContext = ctx;
|
||||
mHandler = handler;
|
||||
mAvoidBadWifiCallback = avoidBadWifiCallback;
|
||||
mSettingsUris = Arrays.asList(
|
||||
Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
|
||||
Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
|
||||
mResolver = mContext.getContentResolver();
|
||||
mSettingObserver = new SettingObserver();
|
||||
mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
reevaluateInternal();
|
||||
}
|
||||
};
|
||||
|
||||
ctx.getSystemService(TelephonyManager.class).listen(
|
||||
new PhoneStateListener(handler.getLooper()) {
|
||||
@Override
|
||||
public void onActiveDataSubscriptionIdChanged(int subId) {
|
||||
mActiveSubId = subId;
|
||||
reevaluateInternal();
|
||||
}
|
||||
}, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
|
||||
|
||||
updateAvoidBadWifi();
|
||||
updateMeteredMultipathPreference();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
for (Uri uri : mSettingsUris) {
|
||||
mResolver.registerContentObserver(uri, false, mSettingObserver);
|
||||
}
|
||||
|
||||
final IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
|
||||
mContext.registerReceiverForAllUsers(mBroadcastReceiver, intentFilter,
|
||||
null /* broadcastPermission */, mHandler);
|
||||
|
||||
reevaluate();
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
mResolver.unregisterContentObserver(mSettingObserver);
|
||||
|
||||
mContext.unregisterReceiver(mBroadcastReceiver);
|
||||
}
|
||||
|
||||
public boolean getAvoidBadWifi() {
|
||||
return mAvoidBadWifi;
|
||||
}
|
||||
|
||||
// TODO: move this to MultipathPolicyTracker.
|
||||
public int getMeteredMultipathPreference() {
|
||||
return mMeteredMultipathPreference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the device or carrier configuration disables avoiding bad wifi by default.
|
||||
*/
|
||||
public boolean configRestrictsAvoidBadWifi() {
|
||||
return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Resources getResourcesForActiveSubId() {
|
||||
return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we should display a notification when wifi becomes unvalidated.
|
||||
*/
|
||||
public boolean shouldNotifyWifiUnvalidated() {
|
||||
return configRestrictsAvoidBadWifi() && getAvoidBadWifiSetting() == null;
|
||||
}
|
||||
|
||||
public String getAvoidBadWifiSetting() {
|
||||
return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void reevaluate() {
|
||||
mHandler.post(this::reevaluateInternal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reevaluate the settings. Must be called on the handler thread.
|
||||
*/
|
||||
private void reevaluateInternal() {
|
||||
if (updateAvoidBadWifi() && mAvoidBadWifiCallback != null) {
|
||||
mAvoidBadWifiCallback.run();
|
||||
}
|
||||
updateMeteredMultipathPreference();
|
||||
}
|
||||
|
||||
public boolean updateAvoidBadWifi() {
|
||||
final boolean settingAvoidBadWifi = "1".equals(getAvoidBadWifiSetting());
|
||||
final boolean prev = mAvoidBadWifi;
|
||||
mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
|
||||
return mAvoidBadWifi != prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default (device and carrier-dependent) value for metered multipath preference.
|
||||
*/
|
||||
public int configMeteredMultipathPreference() {
|
||||
return mContext.getResources().getInteger(
|
||||
R.integer.config_networkMeteredMultipathPreference);
|
||||
}
|
||||
|
||||
public void updateMeteredMultipathPreference() {
|
||||
String setting = Settings.Global.getString(mResolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
|
||||
try {
|
||||
mMeteredMultipathPreference = Integer.parseInt(setting);
|
||||
} catch (NumberFormatException e) {
|
||||
mMeteredMultipathPreference = configMeteredMultipathPreference();
|
||||
}
|
||||
}
|
||||
|
||||
private class SettingObserver extends ContentObserver {
|
||||
public SettingObserver() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
Log.wtf(TAG, "Should never be reached.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
if (!mSettingsUris.contains(uri)) {
|
||||
Log.wtf(TAG, "Unexpected settings observation: " + uri);
|
||||
}
|
||||
reevaluate();
|
||||
}
|
||||
}
|
||||
}
|
||||
121
framework/src/android/net/util/SocketUtils.java
Normal file
121
framework/src/android/net/util/SocketUtils.java
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.util;
|
||||
|
||||
import static android.system.OsConstants.SOL_SOCKET;
|
||||
import static android.system.OsConstants.SO_BINDTODEVICE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.net.NetworkUtils;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.NetlinkSocketAddress;
|
||||
import android.system.Os;
|
||||
import android.system.PacketSocketAddress;
|
||||
|
||||
import libcore.io.IoBridge;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketAddress;
|
||||
|
||||
/**
|
||||
* Collection of utilities to interact with raw sockets.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public final class SocketUtils {
|
||||
/**
|
||||
* Create a raw datagram socket that is bound to an interface.
|
||||
*
|
||||
* <p>Data sent through the socket will go directly to the underlying network, ignoring VPNs.
|
||||
*/
|
||||
public static void bindSocketToInterface(@NonNull FileDescriptor socket, @NonNull String iface)
|
||||
throws ErrnoException {
|
||||
// SO_BINDTODEVICE actually takes a string. This works because the first member
|
||||
// of struct ifreq is a NULL-terminated interface name.
|
||||
// TODO: add a setsockoptString()
|
||||
Os.setsockoptIfreq(socket, SOL_SOCKET, SO_BINDTODEVICE, iface);
|
||||
NetworkUtils.protectFromVpn(socket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a socket address to communicate with netlink.
|
||||
*/
|
||||
@NonNull
|
||||
public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) {
|
||||
return new NetlinkSocketAddress(portId, groupsMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make socket address that packet sockets can bind to.
|
||||
*
|
||||
* @param protocol the layer 2 protocol of the packets to receive. One of the {@code ETH_P_*}
|
||||
* constants in {@link android.system.OsConstants}.
|
||||
* @param ifIndex the interface index on which packets will be received.
|
||||
*/
|
||||
@NonNull
|
||||
public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) {
|
||||
return new PacketSocketAddress(
|
||||
protocol /* sll_protocol */,
|
||||
ifIndex /* sll_ifindex */,
|
||||
null /* sll_addr */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a socket address that packet socket can send packets to.
|
||||
* @deprecated Use {@link #makePacketSocketAddress(int, int, byte[])} instead.
|
||||
*
|
||||
* @param ifIndex the interface index on which packets will be sent.
|
||||
* @param hwAddr the hardware address to which packets will be sent.
|
||||
*/
|
||||
@Deprecated
|
||||
@NonNull
|
||||
public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) {
|
||||
return new PacketSocketAddress(
|
||||
0 /* sll_protocol */,
|
||||
ifIndex /* sll_ifindex */,
|
||||
hwAddr /* sll_addr */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a socket address that a packet socket can send packets to.
|
||||
*
|
||||
* @param protocol the layer 2 protocol of the packets to send. One of the {@code ETH_P_*}
|
||||
* constants in {@link android.system.OsConstants}.
|
||||
* @param ifIndex the interface index on which packets will be sent.
|
||||
* @param hwAddr the hardware address to which packets will be sent.
|
||||
*/
|
||||
@NonNull
|
||||
public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex,
|
||||
@NonNull byte[] hwAddr) {
|
||||
return new PacketSocketAddress(
|
||||
protocol /* sll_protocol */,
|
||||
ifIndex /* sll_ifindex */,
|
||||
hwAddr /* sll_addr */);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor)
|
||||
*/
|
||||
public static void closeSocket(@Nullable FileDescriptor fd) throws IOException {
|
||||
IoBridge.closeAndSignalBlockedThreads(fd);
|
||||
}
|
||||
|
||||
private SocketUtils() {}
|
||||
}
|
||||
Reference in New Issue
Block a user