Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8e39c04b authored by Chalard Jean's avatar Chalard Jean Committed by Gerrit Code Review
Browse files

Merge "Add Qos Callback support"

parents d3464463 2cc8ead3
Loading
Loading
Loading
Loading
+69 −0
Original line number Diff line number Diff line
@@ -6019,6 +6019,7 @@ package android.net {
    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
    method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
    method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
@@ -6028,6 +6029,7 @@ package android.net {
    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
    method public void unregisterQosCallback(@NonNull android.net.QosCallback);
    method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
    field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
    field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
@@ -6221,6 +6223,8 @@ package android.net {
    method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
    method public void onAutomaticReconnectDisabled();
    method public void onNetworkUnwanted();
    method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
    method public void onQosCallbackUnregistered(int);
    method public void onRemoveKeepalivePacketFilter(int);
    method public void onSaveAcceptUnvalidated(boolean);
    method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
@@ -6231,6 +6235,9 @@ package android.net {
    method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
    method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
    method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
    method public final void sendQosCallbackError(int, int);
    method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
    method public final void sendQosSessionLost(int, int);
    method public final void sendSocketKeepaliveEvent(int, int);
    method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
    method public void unregister();
@@ -6317,6 +6324,9 @@ package android.net {
    method public abstract void onRequestScores(android.net.NetworkKey[]);
  }
  public class NetworkReleasedException extends java.lang.Exception {
  }
  public class NetworkRequest implements android.os.Parcelable {
    method @Nullable public String getRequestorPackageName();
    method public int getRequestorUid();
@@ -6389,6 +6399,46 @@ package android.net {
    ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
  }
  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();
  }
  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);
@@ -6434,6 +6484,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);
@@ -10764,6 +10820,19 @@ package android.telephony.data {
    field public static final int RESULT_SUCCESS = 0; // 0x0
  }
  public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
    method @NonNull public static android.telephony.data.EpsBearerQosSessionAttributes create(@NonNull android.os.Parcel);
    method public int describeContents();
    method public long getGuaranteedDownlinkBitRate();
    method public long getGuaranteedUplinkBitRate();
    method public long getMaxDownlinkBitRate();
    method public long getMaxUplinkBitRate();
    method public int getQci();
    method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
  }
  public abstract class QualifiedNetworksService extends android.app.Service {
    ctor public QualifiedNetworksService();
    method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
+115 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import static android.net.IpSecManager.INVALID_RESOURCE_ID;
import static android.net.NetworkRequest.Type.LISTEN;
import static android.net.NetworkRequest.Type.REQUEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
import static android.net.QosCallback.QosCallbackRegistrationException;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -4849,4 +4850,118 @@ public class ConnectivityManager {
        Log.d(TAG, "setOemNetworkPreference called with preference: "
                + preference.toString());
    }

    @NonNull
    private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();

    /**
     * Registers a {@link QosSocketInfo} with an associated {@link QosCallback}.  The callback will
     * receive available QoS events related to the {@link Network} and local ip + port
     * specified within socketInfo.
     * <p/>
     * The same {@link QosCallback} must be unregistered before being registered a second time,
     * otherwise {@link QosCallbackRegistrationException} is thrown.
     * <p/>
     * This API does not, in itself, require any permission if called with a network that is not
     * restricted. However, the underlying implementation currently only supports the IMS network,
     * which is always restricted. That means non-preinstalled callers can't possibly find this API
     * useful, because they'd never be called back on networks that they would have access to.
     *
     * @throws SecurityException if {@link QosSocketInfo#getNetwork()} is restricted and the app is
     * missing CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
     * @throws QosCallback.QosCallbackRegistrationException if qosCallback is already registered.
     * @throws RuntimeException if the app already has too many callbacks registered.
     *
     * Exceptions after the time of registration is passed through
     * {@link QosCallback#onError(QosCallbackException)}.  see: {@link QosCallbackException}.
     *
     * @param socketInfo the socket information used to match QoS events
     * @param callback receives qos events that satisfy socketInfo
     * @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.
     *
     * @hide
     */
    @SystemApi
    public void registerQosCallback(@NonNull final QosSocketInfo socketInfo,
            @NonNull final QosCallback callback,
            @CallbackExecutor @NonNull final Executor executor) {
        Objects.requireNonNull(socketInfo, "socketInfo must be non-null");
        Objects.requireNonNull(callback, "callback must be non-null");
        Objects.requireNonNull(executor, "executor must be non-null");

        try {
            synchronized (mQosCallbackConnections) {
                if (getQosCallbackConnection(callback) == null) {
                    final QosCallbackConnection connection =
                            new QosCallbackConnection(this, callback, executor);
                    mQosCallbackConnections.add(connection);
                    mService.registerQosSocketCallback(socketInfo, connection);
                } else {
                    Log.e(TAG, "registerQosCallback: Callback already registered");
                    throw new QosCallbackRegistrationException();
                }
            }
        } catch (final RemoteException e) {
            Log.e(TAG, "registerQosCallback: Error while registering ", e);

            // The same unregister method method is called for consistency even though nothing
            // will be sent to the ConnectivityService since the callback was never successfully
            // registered.
            unregisterQosCallback(callback);
            e.rethrowFromSystemServer();
        } catch (final ServiceSpecificException e) {
            Log.e(TAG, "registerQosCallback: Error while registering ", e);
            unregisterQosCallback(callback);
            throw convertServiceException(e);
        }
    }

    /**
     * Unregisters the given {@link QosCallback}.  The {@link QosCallback} will no longer receive
     * events once unregistered and can be registered a second time.
     * <p/>
     * If the {@link QosCallback} does not have an active registration, it is a no-op.
     *
     * @param callback the callback being unregistered
     *
     * @hide
     */
    @SystemApi
    public void unregisterQosCallback(@NonNull final QosCallback callback) {
        Objects.requireNonNull(callback, "The callback must be non-null");
        try {
            synchronized (mQosCallbackConnections) {
                final QosCallbackConnection connection = getQosCallbackConnection(callback);
                if (connection != null) {
                    connection.stopReceivingMessages();
                    mService.unregisterQosCallback(connection);
                    mQosCallbackConnections.remove(connection);
                } else {
                    Log.d(TAG, "unregisterQosCallback: Callback not registered");
                }
            }
        } catch (final RemoteException e) {
            Log.e(TAG, "unregisterQosCallback: Error while unregistering ", e);
            e.rethrowFromSystemServer();
        }
    }

    /**
     * Gets the connection related to the callback.
     *
     * @param callback the callback to look up
     * @return the related connection
     */
    @Nullable
    private QosCallbackConnection getQosCallbackConnection(final QosCallback callback) {
        for (final QosCallbackConnection connection : mQosCallbackConnections) {
            // Checking by reference here is intentional
            if (connection.getCallback() == callback) {
                return connection;
            }
        }
        return null;
    }
}
+6 −1
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ 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;
@@ -27,9 +29,9 @@ import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo;
import android.net.UidRange;
import android.net.QosSocketInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkActivityListener;
@@ -239,4 +241,7 @@ interface IConnectivityManager
    void unregisterNetworkActivityListener(in INetworkActivityListener l);

    boolean isDefaultNetworkActive();

    void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
    void unregisterQosCallback(in IQosCallback callback);
}
+34 −0
Original line number Diff line number Diff line
/*
 * 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);
}
+113 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
import android.util.Log;

import com.android.connectivity.aidl.INetworkAgent;
@@ -341,6 +342,24 @@ public abstract class NetworkAgent {
     */
    private static final int EVENT_AGENT_DISCONNECTED = BASE + 19;

    /**
     * Sent by QosCallbackTracker to {@link NetworkAgent} to register a new filter with
     * callback.
     *
     * arg1 = QoS agent callback ID
     * obj = {@link QosFilter}
     * @hide
     */
    public static final int CMD_REGISTER_QOS_CALLBACK = BASE + 20;

    /**
     * Sent by QosCallbackTracker to {@link NetworkAgent} to unregister a callback.
     *
     * arg1 = QoS agent callback ID
     * @hide
     */
    public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;

    private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
        // The subtype can be changed with (TODO) setLegacySubtype, but it starts
        // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
@@ -520,6 +539,17 @@ public abstract class NetworkAgent {
                    onRemoveKeepalivePacketFilter(msg.arg1 /* slot */);
                    break;
                }
                case CMD_REGISTER_QOS_CALLBACK: {
                    onQosCallbackRegistered(
                            msg.arg1 /* QoS callback id */,
                            (QosFilter) msg.obj /* QoS filter */);
                    break;
                }
                case CMD_UNREGISTER_QOS_CALLBACK: {
                    onQosCallbackUnregistered(
                            msg.arg1 /* QoS callback id */);
                    break;
                }
            }
        }
    }
@@ -553,6 +583,8 @@ public abstract class NetworkAgent {
    }

    private static class NetworkAgentBinder extends INetworkAgent.Stub {
        private static final String LOG_TAG = NetworkAgentBinder.class.getSimpleName();

        private final Handler mHandler;

        private NetworkAgentBinder(Handler handler) {
@@ -639,6 +671,25 @@ public abstract class NetworkAgent {
            mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
                    slot, 0));
        }

        @Override
        public void onQosFilterCallbackRegistered(final int qosCallbackId,
                final QosFilterParcelable qosFilterParcelable) {
            if (qosFilterParcelable.getQosFilter() != null) {
                mHandler.sendMessage(
                        mHandler.obtainMessage(CMD_REGISTER_QOS_CALLBACK, qosCallbackId, 0,
                                qosFilterParcelable.getQosFilter()));
                return;
            }

            Log.wtf(LOG_TAG, "onQosFilterCallbackRegistered: qos filter is null.");
        }

        @Override
        public void onQosCallbackUnregistered(final int qosCallbackId) {
            mHandler.sendMessage(mHandler.obtainMessage(
                    CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
        }
    }

    /**
@@ -1067,8 +1118,68 @@ public abstract class NetworkAgent {
    protected void preventAutomaticReconnect() {
    }

    /**
     * Called when a qos callback is registered with a filter.
     * @param qosCallbackId the id for the callback registered
     * @param filter the filter being registered
     */
    public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) {
    }

    /**
     * Called when a qos callback is registered with a filter.
     * <p/>
     * Any QoS events that are sent with the same callback id after this method is called
     * are a no-op.
     *
     * @param qosCallbackId the id for the callback being unregistered
     */
    public void onQosCallbackUnregistered(final int qosCallbackId) {
    }


    /**
     * Sends the attributes of Eps Bearer Qos Session back to the Application
     *
     * @param qosCallbackId the callback id that the session belongs to
     * @param sessionId the unique session id across all Eps Bearer Qos Sessions
     * @param attributes the attributes of the Eps Qos Session
     */
    public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
            @NonNull final EpsBearerQosSessionAttributes attributes) {
        Objects.requireNonNull(attributes, "The attributes must be non-null");
        queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
                new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
                attributes));
    }

    /**
     * Sends event that the Eps Qos Session was lost.
     *
     * @param qosCallbackId the callback id that the session belongs to
     * @param sessionId the unique session id across all Eps Bearer Qos Sessions
     */
    public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) {
        queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
                new QosSession(sessionId, QosSession.TYPE_EPS_BEARER)));
    }

    /**
     * Sends the exception type back to the application.
     *
     * The NetworkAgent should not send anymore messages with this id.
     *
     * @param qosCallbackId the callback id this exception belongs to
     * @param exceptionType the type of exception
     */
    public final void sendQosCallbackError(final int qosCallbackId,
            @QosCallbackException.ExceptionType final int exceptionType) {
        queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType));
    }


    /** @hide */
    protected void log(String s) {
    protected void log(final String s) {
        Log.d(LOG_TAG, "NetworkAgent: " + s);
    }
}
Loading