Merge "Move QoS API classes to Connectivity" am: 32a606fe54

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1611876

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Idad1f51e7f269c2cef9e836efa668a5a0afd4c5a
This commit is contained in:
Remi NGUYEN VAN
2021-03-02 01:28:59 +00:00
committed by Automerger Merge Worker
17 changed files with 1246 additions and 0 deletions

View File

@@ -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 QosFilterParcelable;

View File

@@ -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 QosSession;

View File

@@ -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 QosSocketInfo;

View File

@@ -308,6 +308,9 @@ package android.net {
field public static final int ID_NONE = -1; // 0xffffffff
}
public class NetworkReleasedException extends java.lang.Exception {
}
public class NetworkRequest implements android.os.Parcelable {
method @Nullable public String getRequestorPackageName();
method public int getRequestorUid();
@@ -317,6 +320,47 @@ package android.net {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
}
public abstract class QosCallback {
ctor public QosCallback();
method public void onError(@NonNull android.net.QosCallbackException);
method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
method public void onQosSessionLost(@NonNull android.net.QosSession);
}
public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
}
public final class QosCallbackException extends java.lang.Exception {
}
public abstract class QosFilter {
method @NonNull public abstract android.net.Network getNetwork();
method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
}
public final class QosSession implements android.os.Parcelable {
ctor public QosSession(int, int);
method public int describeContents();
method public int getSessionId();
method public int getSessionType();
method public long getUniqueId();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
field public static final int TYPE_EPS_BEARER = 1; // 0x1
}
public interface QosSessionAttributes {
}
public final class QosSocketInfo implements android.os.Parcelable {
ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
method public int describeContents();
method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
method @NonNull public android.net.Network getNetwork();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
}
public final class RouteInfo implements android.os.Parcelable {
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
@@ -331,6 +375,12 @@ package android.net {
field public static final int SUCCESS = 0; // 0x0
}
public class SocketLocalAddressChangedException extends java.lang.Exception {
}
public class SocketNotBoundException extends java.lang.Exception {
}
public final class StaticIpConfiguration implements android.os.Parcelable {
ctor public StaticIpConfiguration();
ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);

View File

@@ -0,0 +1,34 @@
/*
* 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.os.Bundle;
import android.net.QosSession;
import android.telephony.data.EpsBearerQosSessionAttributes;
/**
* AIDL interface for QosCallback
*
* @hide
*/
oneway interface IQosCallback
{
void onQosEpsBearerSessionAvailable(in QosSession session,
in EpsBearerQosSessionAttributes attributes);
void onQosSessionLost(in QosSession session);
void onError(in int type);
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.SystemApi;
/**
* Indicates that the {@link Network} was released and is no longer available.
*
* @hide
*/
@SystemApi
public class NetworkReleasedException extends Exception {
/** @hide */
public NetworkReleasedException() {
super("The network was released and is no longer available");
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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.SystemApi;
import java.util.concurrent.Executor;
/**
* Receives Qos information given a {@link Network}. The callback is registered with
* {@link ConnectivityManager#registerQosCallback}.
*
* <p>
* <br/>
* The callback will no longer receive calls if any of the following takes place:
* <ol>
* <li>{@link ConnectivityManager#unregisterQosCallback(QosCallback)} is called with the same
* callback instance.</li>
* <li>{@link QosCallback#onError(QosCallbackException)} is called.</li>
* <li>A network specific issue occurs. eg. Congestion on a carrier network.</li>
* <li>The network registered with the callback has no associated QoS providers</li>
* </ul>
* {@hide}
*/
@SystemApi
public abstract class QosCallback {
/**
* Invoked after an error occurs on a registered callback. Once called, the callback is
* automatically unregistered and the callback will no longer receive calls.
*
* <p>The underlying exception can either be a runtime exception or a custom exception made for
* {@link QosCallback}. see: {@link QosCallbackException}.
*
* @param exception wraps the underlying cause
*/
public void onError(@NonNull final QosCallbackException exception) {
}
/**
* Called when a Qos Session first becomes available to the callback or if its attributes have
* changed.
* <p>
* Note: The callback may be called multiple times with the same attributes.
*
* @param session the available session
* @param sessionAttributes the attributes of the session
*/
public void onQosSessionAvailable(@NonNull final QosSession session,
@NonNull final QosSessionAttributes sessionAttributes) {
}
/**
* Called after a Qos Session is lost.
* <p>
* At least one call to
* {@link QosCallback#onQosSessionAvailable(QosSession, QosSessionAttributes)}
* with the same {@link QosSession} will precede a call to lost.
*
* @param session the lost session
*/
public void onQosSessionLost(@NonNull final QosSession session) {
}
/**
* Thrown when there is a problem registering {@link QosCallback} with
* {@link ConnectivityManager#registerQosCallback(QosSocketInfo, QosCallback, Executor)}.
*/
public static class QosCallbackRegistrationException extends RuntimeException {
/**
* @hide
*/
public QosCallbackRegistrationException() {
super();
}
}
}

View File

@@ -0,0 +1,128 @@
/*
* 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.telephony.data.EpsBearerQosSessionAttributes;
import com.android.internal.annotations.VisibleForTesting;
import java.util.Objects;
import java.util.concurrent.Executor;
/**
* Sends messages from {@link com.android.server.ConnectivityService} to the registered
* {@link QosCallback}.
* <p/>
* This is a satellite class of {@link ConnectivityManager} and not meant
* to be used in other contexts.
*
* @hide
*/
class QosCallbackConnection extends android.net.IQosCallback.Stub {
@NonNull private final ConnectivityManager mConnectivityManager;
@Nullable private volatile QosCallback mCallback;
@NonNull private final Executor mExecutor;
@VisibleForTesting
@Nullable
public QosCallback getCallback() {
return mCallback;
}
/**
* The constructor for the connection
*
* @param connectivityManager the mgr that created this connection
* @param callback the callback to send messages back to
* @param executor The executor on which the callback will be invoked. The provided
* {@link Executor} must run callback sequentially, otherwise the order of
* callbacks cannot be guaranteed.
*/
QosCallbackConnection(@NonNull final ConnectivityManager connectivityManager,
@NonNull final QosCallback callback,
@NonNull final Executor executor) {
mConnectivityManager = Objects.requireNonNull(connectivityManager,
"connectivityManager must be non-null");
mCallback = Objects.requireNonNull(callback, "callback must be non-null");
mExecutor = Objects.requireNonNull(executor, "executor must be non-null");
}
/**
* Called when either the {@link EpsBearerQosSessionAttributes} has changed or on the first time
* the attributes have become available.
*
* @param session the session that is now available
* @param attributes the corresponding attributes of session
*/
@Override
public void onQosEpsBearerSessionAvailable(@NonNull final QosSession session,
@NonNull final EpsBearerQosSessionAttributes attributes) {
mExecutor.execute(() -> {
final QosCallback callback = mCallback;
if (callback != null) {
callback.onQosSessionAvailable(session, attributes);
}
});
}
/**
* Called when the session is lost.
*
* @param session the session that was lost
*/
@Override
public void onQosSessionLost(@NonNull final QosSession session) {
mExecutor.execute(() -> {
final QosCallback callback = mCallback;
if (callback != null) {
callback.onQosSessionLost(session);
}
});
}
/**
* Called when there is an error on the registered callback.
*
* @param errorType the type of error
*/
@Override
public void onError(@QosCallbackException.ExceptionType final int errorType) {
mExecutor.execute(() -> {
final QosCallback callback = mCallback;
if (callback != null) {
// Messages no longer need to be received since there was an error.
stopReceivingMessages();
mConnectivityManager.unregisterQosCallback(callback);
callback.onError(QosCallbackException.createException(errorType));
}
});
}
/**
* The callback will stop receiving messages.
* <p/>
* There are no synchronization guarantees on exactly when the callback will stop receiving
* messages.
*/
void stopReceivingMessages() {
mCallback = null;
}
}

View File

@@ -0,0 +1,110 @@
/*
* 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.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* This is the exception type passed back through the onError method on {@link QosCallback}.
* {@link QosCallbackException#getCause()} contains the actual error that caused this exception.
*
* The possible exception types as causes are:
* 1. {@link NetworkReleasedException}
* 2. {@link SocketNotBoundException}
* 3. {@link UnsupportedOperationException}
* 4. {@link SocketLocalAddressChangedException}
*
* @hide
*/
@SystemApi
public final class QosCallbackException extends Exception {
/** @hide */
@IntDef(prefix = {"EX_TYPE_"}, value = {
EX_TYPE_FILTER_NONE,
EX_TYPE_FILTER_NETWORK_RELEASED,
EX_TYPE_FILTER_SOCKET_NOT_BOUND,
EX_TYPE_FILTER_NOT_SUPPORTED,
EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ExceptionType {}
private static final String TAG = "QosCallbackException";
// Types of exceptions supported //
/** {@hide} */
public static final int EX_TYPE_FILTER_NONE = 0;
/** {@hide} */
public static final int EX_TYPE_FILTER_NETWORK_RELEASED = 1;
/** {@hide} */
public static final int EX_TYPE_FILTER_SOCKET_NOT_BOUND = 2;
/** {@hide} */
public static final int EX_TYPE_FILTER_NOT_SUPPORTED = 3;
/** {@hide} */
public static final int EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED = 4;
/**
* Creates exception based off of a type and message. Not all types of exceptions accept a
* custom message.
*
* {@hide}
*/
@NonNull
static QosCallbackException createException(@ExceptionType final int type) {
switch (type) {
case EX_TYPE_FILTER_NETWORK_RELEASED:
return new QosCallbackException(new NetworkReleasedException());
case EX_TYPE_FILTER_SOCKET_NOT_BOUND:
return new QosCallbackException(new SocketNotBoundException());
case EX_TYPE_FILTER_NOT_SUPPORTED:
return new QosCallbackException(new UnsupportedOperationException(
"This device does not support the specified filter"));
case EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED:
return new QosCallbackException(
new SocketLocalAddressChangedException());
default:
Log.wtf(TAG, "create: No case setup for exception type: '" + type + "'");
return new QosCallbackException(
new RuntimeException("Unknown exception code: " + type));
}
}
/**
* @hide
*/
public QosCallbackException(@NonNull final String message) {
super(message);
}
/**
* @hide
*/
public QosCallbackException(@NonNull final Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.SystemApi;
import java.net.InetAddress;
/**
* Provides the related filtering logic to the {@link NetworkAgent} to match {@link QosSession}s
* to their related {@link QosCallback}.
*
* Used by the {@link com.android.server.ConnectivityService} to validate a {@link QosCallback}
* is still able to receive a {@link QosSession}.
*
* @hide
*/
@SystemApi
public abstract class QosFilter {
/**
* The constructor is kept hidden from outside this package to ensure that all derived types
* are known and properly handled when being passed to and from {@link NetworkAgent}.
*
* @hide
*/
QosFilter() {
}
/**
* The network used with this filter.
*
* @return the registered {@link Network}
*/
@NonNull
public abstract Network getNetwork();
/**
* Validates that conditions have not changed such that no further {@link QosSession}s should
* be passed back to the {@link QosCallback} associated to this filter.
*
* @return the error code when present, otherwise the filter is valid
*
* @hide
*/
@QosCallbackException.ExceptionType
public abstract int validate();
/**
* Determines whether or not the parameters is a match for the filter.
*
* @param address the local address
* @param startPort the start of the port range
* @param endPort the end of the port range
* @return whether the parameters match the local address of the filter
*/
public abstract boolean matchesLocalAddress(@NonNull InetAddress address,
int startPort, int endPort);
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import java.util.Objects;
/**
* Aware of how to parcel different types of {@link QosFilter}s. Any new type of qos filter must
* have a specialized case written here.
* <p/>
* Specifically leveraged when transferring {@link QosFilter} from
* {@link com.android.server.ConnectivityService} to {@link NetworkAgent} when the filter is first
* registered.
* <p/>
* This is not meant to be used in other contexts.
*
* @hide
*/
public final class QosFilterParcelable implements Parcelable {
private static final String LOG_TAG = QosFilterParcelable.class.getSimpleName();
// Indicates that the filter was not successfully written to the parcel.
private static final int NO_FILTER_PRESENT = 0;
// The parcel is of type qos socket filter.
private static final int QOS_SOCKET_FILTER = 1;
private final QosFilter mQosFilter;
/**
* The underlying qos filter.
* <p/>
* Null only in the case parceling failed.
*/
@Nullable
public QosFilter getQosFilter() {
return mQosFilter;
}
public QosFilterParcelable(@NonNull final QosFilter qosFilter) {
Objects.requireNonNull(qosFilter, "qosFilter must be non-null");
// NOTE: Normally a type check would belong here, but doing so breaks unit tests that rely
// on mocking qos filter.
mQosFilter = qosFilter;
}
private QosFilterParcelable(final Parcel in) {
final int filterParcelType = in.readInt();
switch (filterParcelType) {
case QOS_SOCKET_FILTER: {
mQosFilter = new QosSocketFilter(QosSocketInfo.CREATOR.createFromParcel(in));
break;
}
case NO_FILTER_PRESENT:
default: {
mQosFilter = null;
}
}
}
public static final Creator<QosFilterParcelable> CREATOR = new Creator<QosFilterParcelable>() {
@Override
public QosFilterParcelable createFromParcel(final Parcel in) {
return new QosFilterParcelable(in);
}
@Override
public QosFilterParcelable[] newArray(final int size) {
return new QosFilterParcelable[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
if (mQosFilter instanceof QosSocketFilter) {
dest.writeInt(QOS_SOCKET_FILTER);
final QosSocketFilter qosSocketFilter = (QosSocketFilter) mQosFilter;
qosSocketFilter.getQosSocketInfo().writeToParcel(dest, 0);
return;
}
dest.writeInt(NO_FILTER_PRESENT);
Log.e(LOG_TAG, "Parceling failed, unknown type of filter present: " + mQosFilter);
}
}

View File

@@ -0,0 +1,136 @@
/*
* 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.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Provides identifying information of a QoS session. Sent to an application through
* {@link QosCallback}.
*
* @hide
*/
@SystemApi
public final class QosSession implements Parcelable {
/**
* The {@link QosSession} is a LTE EPS Session.
*/
public static final int TYPE_EPS_BEARER = 1;
private final int mSessionId;
private final int mSessionType;
/**
* Gets the unique id of the session that is used to differentiate sessions across different
* types.
* <p/>
* Note: Different qos sessions can be provided by different actors.
*
* @return the unique id
*/
public long getUniqueId() {
return (long) mSessionType << 32 | mSessionId;
}
/**
* Gets the session id that is unique within that type.
* <p/>
* Note: The session id is set by the actor providing the qos. It can be either manufactured by
* the actor, but also may have a particular meaning within that type. For example, using the
* bearer id as the session id for {@link android.telephony.data.EpsBearerQosSessionAttributes}
* is a straight forward way to keep the sessions unique from one another within that type.
*
* @return the id of the session
*/
public int getSessionId() {
return mSessionId;
}
/**
* Gets the type of session.
*/
@QosSessionType
public int getSessionType() {
return mSessionType;
}
/**
* Creates a {@link QosSession}.
*
* @param sessionId uniquely identifies the session across all sessions of the same type
* @param sessionType the type of session
*/
public QosSession(final int sessionId, @QosSessionType final int sessionType) {
//Ensures the session id is unique across types of sessions
mSessionId = sessionId;
mSessionType = sessionType;
}
@Override
public String toString() {
return "QosSession{"
+ "mSessionId=" + mSessionId
+ ", mSessionType=" + mSessionType
+ '}';
}
/**
* Annotations for types of qos sessions.
*/
@IntDef(value = {
TYPE_EPS_BEARER,
})
@interface QosSessionType {}
private QosSession(final Parcel in) {
mSessionId = in.readInt();
mSessionType = in.readInt();
}
@NonNull
public static final Creator<QosSession> CREATOR = new Creator<QosSession>() {
@NonNull
@Override
public QosSession createFromParcel(@NonNull final Parcel in) {
return new QosSession(in);
}
@NonNull
@Override
public QosSession[] newArray(final int size) {
return new QosSession[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull final Parcel dest, final int flags) {
dest.writeInt(mSessionId);
dest.writeInt(mSessionType);
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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.SystemApi;
/**
* Implemented by classes that encapsulate Qos related attributes that describe a Qos Session.
*
* Use the instanceof keyword to determine the underlying type.
*
* @hide
*/
@SystemApi
public interface QosSessionAttributes {
}

View File

@@ -0,0 +1,166 @@
/*
* 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 static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.ParcelFileDescriptor;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import java.io.FileDescriptor;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Objects;
/**
* Filters a {@link QosSession} according to the binding on the provided {@link Socket}.
*
* @hide
*/
public class QosSocketFilter extends QosFilter {
private static final String TAG = QosSocketFilter.class.getSimpleName();
@NonNull
private final QosSocketInfo mQosSocketInfo;
/**
* Creates a {@link QosSocketFilter} based off of {@link QosSocketInfo}.
*
* @param qosSocketInfo the information required to filter and validate
*/
public QosSocketFilter(@NonNull final QosSocketInfo qosSocketInfo) {
Objects.requireNonNull(qosSocketInfo, "qosSocketInfo must be non-null");
mQosSocketInfo = qosSocketInfo;
}
/**
* Gets the parcelable qos socket info that was used to create the filter.
*/
@NonNull
public QosSocketInfo getQosSocketInfo() {
return mQosSocketInfo;
}
/**
* Performs two validations:
* 1. If the socket is not bound, then return
* {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND}. This is detected
* by checking the local address on the filter which becomes null when the socket is no
* longer bound.
* 2. In the scenario that the socket is now bound to a different local address, which can
* happen in the case of UDP, then
* {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED} is returned.
* @return validation error code
*/
@Override
public int validate() {
final InetSocketAddress sa = getAddressFromFileDescriptor();
if (sa == null) {
return QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND;
}
if (!sa.equals(mQosSocketInfo.getLocalSocketAddress())) {
return EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
}
return EX_TYPE_FILTER_NONE;
}
/**
* The local address of the socket's binding.
*
* Note: If the socket is no longer bound, null is returned.
*
* @return the local address
*/
@Nullable
private InetSocketAddress getAddressFromFileDescriptor() {
final ParcelFileDescriptor parcelFileDescriptor = mQosSocketInfo.getParcelFileDescriptor();
if (parcelFileDescriptor == null) return null;
final FileDescriptor fd = parcelFileDescriptor.getFileDescriptor();
if (fd == null) return null;
final SocketAddress address;
try {
address = Os.getsockname(fd);
} catch (final ErrnoException e) {
Log.e(TAG, "getAddressFromFileDescriptor: getLocalAddress exception", e);
return null;
}
if (address instanceof InetSocketAddress) {
return (InetSocketAddress) address;
}
return null;
}
/**
* The network used with this filter.
*
* @return the registered {@link Network}
*/
@NonNull
@Override
public Network getNetwork() {
return mQosSocketInfo.getNetwork();
}
/**
* @inheritDoc
*/
@Override
public boolean matchesLocalAddress(@NonNull final InetAddress address, final int startPort,
final int endPort) {
if (mQosSocketInfo.getLocalSocketAddress() == null) {
return false;
}
return matchesLocalAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
endPort);
}
/**
* Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)} with the
* filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}.
* <p>
* This method exists for testing purposes since {@link QosSocketInfo} couldn't be mocked
* due to being final.
*
* @param filterSocketAddress the socket address of the filter
* @param address the address to compare the filterSocketAddressWith
* @param startPort the start of the port range to check
* @param endPort the end of the port range to check
*/
@VisibleForTesting
public static boolean matchesLocalAddress(@NonNull final InetSocketAddress filterSocketAddress,
@NonNull final InetAddress address,
final int startPort, final int endPort) {
return startPort <= filterSocketAddress.getPort()
&& endPort >= filterSocketAddress.getPort()
&& filterSocketAddress.getAddress().equals(address);
}
}

View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Objects;
/**
* Used in conjunction with
* {@link ConnectivityManager#registerQosCallback}
* in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}.
*
* @hide
*/
@SystemApi
public final class QosSocketInfo implements Parcelable {
@NonNull
private final Network mNetwork;
@NonNull
private final ParcelFileDescriptor mParcelFileDescriptor;
@NonNull
private final InetSocketAddress mLocalSocketAddress;
/**
* The {@link Network} the socket is on.
*
* @return the registered {@link Network}
*/
@NonNull
public Network getNetwork() {
return mNetwork;
}
/**
* The parcel file descriptor wrapped around the socket's file descriptor.
*
* @return the parcel file descriptor of the socket
*/
@NonNull
ParcelFileDescriptor getParcelFileDescriptor() {
return mParcelFileDescriptor;
}
/**
* The local address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
* The value does not reflect any changes that occur to the socket after it is first set
* in the constructor.
*
* @return the local address of the socket
*/
@NonNull
public InetSocketAddress getLocalSocketAddress() {
return mLocalSocketAddress;
}
/**
* Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}. The
* {@link Socket} must remain bound in order to receive {@link QosSession}s.
*
* @param network the network
* @param socket the bound {@link Socket}
*/
public QosSocketInfo(@NonNull final Network network, @NonNull final Socket socket)
throws IOException {
Objects.requireNonNull(socket, "socket cannot be null");
mNetwork = Objects.requireNonNull(network, "network cannot be null");
mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$());
mLocalSocketAddress =
new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
}
/* Parcelable methods */
private QosSocketInfo(final Parcel in) {
mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
final int addressLength = in.readInt();
mLocalSocketAddress = readSocketAddress(in, addressLength);
}
private InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
final byte[] address = new byte[addressLength];
in.readByteArray(address);
final int port = in.readInt();
try {
return new InetSocketAddress(InetAddress.getByAddress(address), port);
} catch (final UnknownHostException e) {
/* The catch block was purposely left empty. UnknownHostException will never be thrown
since the address provided is numeric and non-null. */
}
return new InetSocketAddress();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull final Parcel dest, final int flags) {
mNetwork.writeToParcel(dest, 0);
mParcelFileDescriptor.writeToParcel(dest, 0);
final byte[] address = mLocalSocketAddress.getAddress().getAddress();
dest.writeInt(address.length);
dest.writeByteArray(address);
dest.writeInt(mLocalSocketAddress.getPort());
}
@NonNull
public static final Parcelable.Creator<QosSocketInfo> CREATOR =
new Parcelable.Creator<QosSocketInfo>() {
@NonNull
@Override
public QosSocketInfo createFromParcel(final Parcel in) {
return new QosSocketInfo(in);
}
@NonNull
@Override
public QosSocketInfo[] newArray(final int size) {
return new QosSocketInfo[size];
}
};
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.SystemApi;
/**
* Thrown when the local address of the socket has changed.
*
* @hide
*/
@SystemApi
public class SocketLocalAddressChangedException extends Exception {
/** @hide */
public SocketLocalAddressChangedException() {
super("The local address of the socket changed");
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.net;
import android.annotation.SystemApi;
/**
* Thrown when a previously bound socket becomes unbound.
*
* @hide
*/
@SystemApi
public class SocketNotBoundException extends Exception {
/** @hide */
public SocketNotBoundException() {
super("The socket is unbound");
}
}