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

Commit 7c469179 authored by junyulai's avatar junyulai
Browse files

[KA02.5] Use binder thread and executor to invoke callback

Currently, client side of keepalive event handling rely on a
newly created thread, looper, messenger and handler per object.

However, by creating oneway AIDL interface with the executor,
the callbacks can be invoked on the binder thread with user
specified context, which not only greatly simplify the design
but also reduce the cost of current thread modeling.

Bug: 114151147
Bug: 123969871
Test: 1. atest FrameworksNetTests --generate-new-metric 10
      2. atest-deflake.sh

Change-Id: I27504074cd28d5b5eb94a7ec0e97ebaaaaa1ae3d
parent 0102e3d5
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@ java_defaults {
        "core/java/android/net/INetworkScoreService.aidl",
        "core/java/android/net/INetworkStatsService.aidl",
        "core/java/android/net/INetworkStatsSession.aidl",
        "core/java/android/net/ISocketKeepaliveCallback.aidl",
        "core/java/android/net/ITestNetworkManager.aidl",
        "core/java/android/net/ITetheringEventCallback.aidl",
        "core/java/android/net/ITetheringStatsProvider.aidl",
+54 −47
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.INetworkActivityListener;
import android.os.INetworkManagementService;
@@ -75,6 +74,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;

/**
 * Class that answers queries about the state of network connectivity. It also
@@ -1813,23 +1815,26 @@ public class ConnectivityManager {
        public static final int MIN_INTERVAL = 10;

        private final Network mNetwork;
        private final PacketKeepaliveCallback mCallback;
        private final Looper mLooper;
        private final Messenger mMessenger;
        private final ISocketKeepaliveCallback mCallback;
        private final ExecutorService mExecutor;

        private volatile Integer mSlot;

        void stopLooper() {
            mLooper.quit();
        }

        @UnsupportedAppUsage
        public void stop() {
            try {
                mExecutor.execute(() -> {
                    try {
                        if (mSlot != null) {
                            mService.stopKeepalive(mNetwork, mSlot);
                        }
                    } catch (RemoteException e) {
                        Log.e(TAG, "Error stopping packet keepalive: ", e);
                stopLooper();
                        throw e.rethrowFromSystemServer();
                    }
                });
            } catch (RejectedExecutionException e) {
                // The internal executor has already stopped due to previous event.
            }
        }

@@ -1837,40 +1842,43 @@ public class ConnectivityManager {
            Preconditions.checkNotNull(network, "network cannot be null");
            Preconditions.checkNotNull(callback, "callback cannot be null");
            mNetwork = network;
            mCallback = callback;
            HandlerThread thread = new HandlerThread(TAG);
            thread.start();
            mLooper = thread.getLooper();
            mMessenger = new Messenger(new Handler(mLooper) {
            mExecutor = Executors.newSingleThreadExecutor();
            mCallback = new ISocketKeepaliveCallback.Stub() {
                @Override
                public void handleMessage(Message message) {
                    switch (message.what) {
                        case NetworkAgent.EVENT_SOCKET_KEEPALIVE:
                            int error = message.arg2;
                            try {
                                if (error == SUCCESS) {
                                    if (mSlot == null) {
                                        mSlot = message.arg1;
                                        mCallback.onStarted();
                                    } else {
                                        mSlot = null;
                                        stopLooper();
                                        mCallback.onStopped();
                                    }
                                } else {
                                    stopLooper();
                                    mCallback.onError(error);
                public void onStarted(int slot) {
                    Binder.withCleanCallingIdentity(() ->
                            mExecutor.execute(() -> {
                                mSlot = slot;
                                callback.onStarted();
                            }));
                }
                            } catch (Exception e) {
                                Log.e(TAG, "Exception in keepalive callback(" + error + ")", e);

                @Override
                public void onStopped() {
                    Binder.withCleanCallingIdentity(() ->
                            mExecutor.execute(() -> {
                                mSlot = null;
                                callback.onStopped();
                            }));
                    mExecutor.shutdown();
                }
                            break;
                        default:
                            Log.e(TAG, "Unhandled message " + Integer.toHexString(message.what));
                            break;

                @Override
                public void onError(int error) {
                    Binder.withCleanCallingIdentity(() ->
                            mExecutor.execute(() -> {
                                mSlot = null;
                                callback.onError(error);
                            }));
                    mExecutor.shutdown();
                }

                @Override
                public void onDataReceived() {
                    // PacketKeepalive is only used for Nat-T keepalive and as such does not invoke
                    // this callback when data is received.
                }
            });
            };
        }
    }

@@ -1887,12 +1895,11 @@ public class ConnectivityManager {
            InetAddress srcAddr, int srcPort, InetAddress dstAddr) {
        final PacketKeepalive k = new PacketKeepalive(network, callback);
        try {
            mService.startNattKeepalive(network, intervalSeconds, k.mMessenger, new Binder(),
            mService.startNattKeepalive(network, intervalSeconds, k.mCallback,
                    srcAddr.getHostAddress(), srcPort, dstAddr.getHostAddress());
        } catch (RemoteException e) {
            Log.e(TAG, "Error starting packet keepalive: ", e);
            k.stopLooper();
            return null;
            throw e.rethrowFromSystemServer();
        }
        return k;
    }
+5 −4
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.net.NetworkMisc;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo;
import android.os.Bundle;
import android.os.IBinder;
@@ -194,15 +195,15 @@ interface IConnectivityManager

    void factoryReset();

    void startNattKeepalive(in Network network, int intervalSeconds, in Messenger messenger,
            in IBinder binder, String srcAddr, int srcPort, String dstAddr);
    void startNattKeepalive(in Network network, int intervalSeconds,
            in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr);

    void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId,
            int intervalSeconds, in Messenger messenger, in IBinder binder, String srcAddr,
            int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr,
            String dstAddr);

    void startTcpKeepalive(in Network network, in FileDescriptor fd, int intervalSeconds,
            in Messenger messenger, in IBinder binder);
            in ISocketKeepaliveCallback cb);

    void stopKeepalive(in Network network, int slot);

+34 −0
Original line number Diff line number Diff line
/**
 * 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();
}
+20 −15
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package android.net;

import android.annotation.NonNull;
import android.os.Binder;
import android.os.RemoteException;
import android.util.Log;

@@ -52,24 +51,30 @@ public final class NattSocketKeepalive extends SocketKeepalive {

    @Override
    void startImpl(int intervalSec) {
        mExecutor.execute(() -> {
            try {
            mService.startNattKeepaliveWithFd(mNetwork, mFd, mResourceId, intervalSec, mMessenger,
                    new Binder(), mSource.getHostAddress(), mDestination.getHostAddress());
                mService.startNattKeepaliveWithFd(mNetwork, mFd, mResourceId, intervalSec,
                        mCallback,
                        mSource.getHostAddress(), mDestination.getHostAddress());
            } catch (RemoteException e) {
            Log.e(TAG, "Error starting packet keepalive: ", e);
            stopLooper();
                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 packet keepalive: ", e);
            stopLooper();
                Log.e(TAG, "Error stopping socket keepalive: ", e);
                throw e.rethrowFromSystemServer();
            }
        });

    }
}
Loading