Add net-utils-services-common library

net-utils-services-common-srcs for files in src_servicescommon
and library net-utils-services-common could be used in services.jar
or modules.

Bug: 138306002
Bug: 139268426
Test: atest FrameworksNetTests FrameworksTelephonyTests
Change-Id: I5043a34100e9ef26148e3a0c1743363d063a3604
Merged-In: I5043a34100e9ef26148e3a0c1743363d063a3604
(clean cherry-pick from internal branch)
diff --git a/staticlibs/Android.bp b/staticlibs/Android.bp
index ffc02c3..5c851fd 100644
--- a/staticlibs/Android.bp
+++ b/staticlibs/Android.bp
@@ -12,9 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// File group "net-utils-framework-common-srcs" is also compiled into android framework.
-// Add jarjar rules here so that anything outside of framework could use this library
-// directly.
+// 1. The "net-utils-framework-common" library is also compiled into the framework and placed on the
+//    boot classpath. It uses jarjar rules so that anything outside the framework can use this
+//    library directly.
+// 2. The "net-utils-services-common" library is for use by modules and frameworks/base/services.
+//    It does not need to be jarjared because it is not placed on the bootclasspath.
 
 filegroup {
     name: "net-utils-framework-common-srcs",
@@ -35,3 +37,16 @@
         "//packages/modules/CaptivePortalLogin",
     ]
 }
+
+java_library {
+    name: "net-utils-services-common",
+    srcs: ["src_servicescommon/**/*.java"],
+    visibility: [
+        "//frameworks/base/services",
+        "//frameworks/base/packages/Tethering",
+        "//frameworks/opt/net/wifi/service",
+        "//frameworks/opt/net/ike",
+        "//packages/modules/NetworkStack",
+        "//packages/modules/CaptivePortalLogin",
+    ],
+}
diff --git a/staticlibs/src_servicescommon/android/net/NetworkFactory.java b/staticlibs/src_servicescommon/android/net/NetworkFactory.java
new file mode 100644
index 0000000..479a191
--- /dev/null
+++ b/staticlibs/src_servicescommon/android/net/NetworkFactory.java
@@ -0,0 +1,449 @@
+/*
+ * 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.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Protocol;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A NetworkFactory is an entity that creates NetworkAgent objects.
+ * The bearers register with ConnectivityService using {@link #register} and
+ * their factory will start receiving scored NetworkRequests.  NetworkRequests
+ * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by
+ * overridden function.  All of these can be dynamic - changing NetworkCapabilities
+ * or score forces re-evaluation of all current requests.
+ *
+ * If any requests pass the filter some overrideable functions will be called.
+ * If the bearer only cares about very simple start/stopNetwork callbacks, those
+ * functions can be overridden.  If the bearer needs more interaction, it can
+ * override addNetworkRequest and removeNetworkRequest which will give it each
+ * request that passes their current filters.
+ * @hide
+ **/
+public class NetworkFactory extends Handler {
+    /* TODO: delete when all callers have migrated to NetworkProvider IDs. */
+    public static class SerialNumber {
+        // Guard used by no network factory.
+        public static final int NONE = -1;
+        // A hardcoded serial number for NetworkAgents representing VPNs. These agents are
+        // not created by any factory, so they use this constant for clarity instead of NONE.
+        public static final int VPN = -2;
+        private static final AtomicInteger sNetworkFactorySerialNumber = new AtomicInteger(1);
+        /** Returns a unique serial number for a factory. */
+        public static final int nextSerialNumber() {
+            return sNetworkFactorySerialNumber.getAndIncrement();
+        }
+    }
+
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    private static final int BASE = Protocol.BASE_NETWORK_FACTORY;
+    /**
+     * Pass a network request to the bearer.  If the bearer believes it can
+     * satisfy the request it should connect to the network and create a
+     * NetworkAgent.  Once the NetworkAgent is fully functional it will
+     * register itself with ConnectivityService using registerNetworkAgent.
+     * If the bearer cannot immediately satisfy the request (no network,
+     * user disabled the radio, lower-scored network) it should remember
+     * any NetworkRequests it may be able to satisfy in the future.  It may
+     * disregard any that it will never be able to service, for example
+     * those requiring a different bearer.
+     * msg.obj = NetworkRequest
+     * msg.arg1 = score - the score of the network currently satisfying this
+     *            request.  If this bearer knows in advance it cannot
+     *            exceed this score it should not try to connect, holding the request
+     *            for the future.
+     *            Note that subsequent events may give a different (lower
+     *            or higher) score for this request, transmitted to each
+     *            NetworkFactory through additional CMD_REQUEST_NETWORK msgs
+     *            with the same NetworkRequest but an updated score.
+     *            Also, network conditions may change for this bearer
+     *            allowing for a better score in the future.
+     * msg.arg2 = the ID of the NetworkProvider currently responsible for the
+     *            NetworkAgent handling this request, or NetworkProvider.ID_NONE if none.
+     */
+    public static final int CMD_REQUEST_NETWORK = BASE;
+
+    /**
+     * Cancel a network request
+     * msg.obj = NetworkRequest
+     */
+    public static final int CMD_CANCEL_REQUEST = BASE + 1;
+
+    /**
+     * Internally used to set our best-guess score.
+     * msg.arg1 = new score
+     */
+    private static final int CMD_SET_SCORE = BASE + 2;
+
+    /**
+     * Internally used to set our current filter for coarse bandwidth changes with
+     * technology changes.
+     * msg.obj = new filter
+     */
+    private static final int CMD_SET_FILTER = BASE + 3;
+
+    private final Context mContext;
+    private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>();
+    private final String LOG_TAG;
+
+    private final SparseArray<NetworkRequestInfo> mNetworkRequests =
+            new SparseArray<NetworkRequestInfo>();
+
+    private int mScore;
+    private NetworkCapabilities mCapabilityFilter;
+
+    private int mRefCount = 0;
+    private Messenger mMessenger = null;
+    private NetworkProvider mProvider = null;
+    private int mProviderId;
+
+    public NetworkFactory(Looper looper, Context context, String logTag,
+            NetworkCapabilities filter) {
+        super(looper);
+        LOG_TAG = logTag;
+        mContext = context;
+        mCapabilityFilter = filter;
+    }
+
+    public void register() {
+        if (mProvider != null) {
+            Log.e(LOG_TAG, "Ignoring attempt to register already-registered NetworkFactory");
+            return;
+        }
+        if (DBG) log("Registering NetworkFactory");
+
+        mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) {
+            @Override
+            public void onNetworkRequested(@NonNull NetworkRequest request, int score,
+                    int servingProviderId) {
+                handleAddRequest((NetworkRequest) request, score, servingProviderId);
+            }
+
+            @Override
+            public void onRequestWithdrawn(@NonNull NetworkRequest request) {
+                handleRemoveRequest(request);
+            }
+        };
+
+        mMessenger = new Messenger(this);
+        mProviderId = ConnectivityManager.from(mContext).registerNetworkProvider(mProvider);
+    }
+
+    public void unregister() {
+        if (mProvider == null) {
+            Log.e(LOG_TAG, "Ignoring attempt to unregister unregistered NetworkFactory");
+            return;
+        }
+        if (DBG) log("Unregistering NetworkFactory");
+
+        ConnectivityManager.from(mContext).unregisterNetworkProvider(mProvider);
+        mProvider = null;
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case CMD_REQUEST_NETWORK: {
+                handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
+                break;
+            }
+            case CMD_CANCEL_REQUEST: {
+                handleRemoveRequest((NetworkRequest) msg.obj);
+                break;
+            }
+            case CMD_SET_SCORE: {
+                handleSetScore(msg.arg1);
+                break;
+            }
+            case CMD_SET_FILTER: {
+                handleSetFilter((NetworkCapabilities) msg.obj);
+                break;
+            }
+        }
+    }
+
+    private class NetworkRequestInfo {
+        public final NetworkRequest request;
+        public int score;
+        public boolean requested; // do we have a request outstanding, limited by score
+        public int providerId;
+
+        NetworkRequestInfo(NetworkRequest request, int score, int providerId) {
+            this.request = request;
+            this.score = score;
+            this.requested = false;
+            this.providerId = providerId;
+        }
+
+        @Override
+        public String toString() {
+            return "{" + request + ", score=" + score + ", requested=" + requested + "}";
+        }
+    }
+
+    /**
+     * Add a NetworkRequest that the bearer may want to attempt to satisfy.
+     * @see #CMD_REQUEST_NETWORK
+     *
+     * @param request the request to handle.
+     * @param score the score of the NetworkAgent currently satisfying this request.
+     */
+    // TODO : remove this method. It is a stopgap measure to help sheperding a number
+    // of dependent changes that would conflict throughout the automerger graph. Having this
+    // temporarily helps with the process of going through with all these dependent changes across
+    // the entire tree.
+    @VisibleForTesting
+    protected void handleAddRequest(NetworkRequest request, int score) {
+        handleAddRequest(request, score, NetworkProvider.ID_NONE);
+    }
+
+    /**
+     * Add a NetworkRequest that the bearer may want to attempt to satisfy.
+     * @see #CMD_REQUEST_NETWORK
+     *
+     * @param request the request to handle.
+     * @param score the score of the NetworkAgent currently satisfying this request.
+     * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent
+     *        currently satisfying this request.
+     */
+    @VisibleForTesting
+    protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) {
+        NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
+        if (n == null) {
+            if (DBG) {
+                log("got request " + request + " with score " + score
+                        + " and providerId " + servingProviderId);
+            }
+            n = new NetworkRequestInfo(request, score, servingProviderId);
+            mNetworkRequests.put(n.request.requestId, n);
+        } else {
+            if (VDBG) {
+                log("new score " + score + " for existing request " + request
+                        + " and providerId " + servingProviderId);
+            }
+            n.score = score;
+            n.providerId = servingProviderId;
+        }
+        if (VDBG) log("  my score=" + mScore + ", my filter=" + mCapabilityFilter);
+
+        evalRequest(n);
+    }
+
+    @VisibleForTesting
+    protected void handleRemoveRequest(NetworkRequest request) {
+        NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
+        if (n != null) {
+            mNetworkRequests.remove(request.requestId);
+            if (n.requested) releaseNetworkFor(n.request);
+        }
+    }
+
+    private void handleSetScore(int score) {
+        mScore = score;
+        evalRequests();
+    }
+
+    private void handleSetFilter(NetworkCapabilities netCap) {
+        mCapabilityFilter = netCap;
+        evalRequests();
+    }
+
+    /**
+     * Overridable function to provide complex filtering.
+     * Called for every request every time a new NetworkRequest is seen
+     * and whenever the filterScore or filterNetworkCapabilities change.
+     *
+     * acceptRequest can be overridden to provide complex filter behavior
+     * for the incoming requests
+     *
+     * For output, this class will call {@link #needNetworkFor} and
+     * {@link #releaseNetworkFor} for every request that passes the filters.
+     * If you don't need to see every request, you can leave the base
+     * implementations of those two functions and instead override
+     * {@link #startNetwork} and {@link #stopNetwork}.
+     *
+     * If you want to see every score fluctuation on every request, set
+     * your score filter to a very high number and watch {@link #needNetworkFor}.
+     *
+     * @return {@code true} to accept the request.
+     */
+    public boolean acceptRequest(NetworkRequest request, int score) {
+        return true;
+    }
+
+    private void evalRequest(NetworkRequestInfo n) {
+        if (VDBG) {
+            log("evalRequest");
+            log(" n.requests = " + n.requested);
+            log(" n.score = " + n.score);
+            log(" mScore = " + mScore);
+            log(" n.providerId = " + n.providerId);
+            log(" mProviderId = " + mProviderId);
+        }
+        if (shouldNeedNetworkFor(n)) {
+            if (VDBG) log("  needNetworkFor");
+            needNetworkFor(n.request, n.score);
+            n.requested = true;
+        } else if (shouldReleaseNetworkFor(n)) {
+            if (VDBG) log("  releaseNetworkFor");
+            releaseNetworkFor(n.request);
+            n.requested = false;
+        } else {
+            if (VDBG) log("  done");
+        }
+    }
+
+    private boolean shouldNeedNetworkFor(NetworkRequestInfo n) {
+        // If this request is already tracked, it doesn't qualify for need
+        return !n.requested
+            // If the score of this request is higher or equal to that of this factory and some
+            // other factory is responsible for it, then this factory should not track the request
+            // because it has no hope of satisfying it.
+            && (n.score < mScore || n.providerId == mProviderId)
+            // If this factory can't satisfy the capability needs of this request, then it
+            // should not be tracked.
+            && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter)
+            // Finally if the concrete implementation of the factory rejects the request, then
+            // don't track it.
+            && acceptRequest(n.request, n.score);
+    }
+
+    private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) {
+        // Don't release a request that's not tracked.
+        return n.requested
+            // The request should be released if it can't be satisfied by this factory. That
+            // means either of the following conditions are met :
+            // - Its score is too high to be satisfied by this factory and it's not already
+            //   assigned to the factory
+            // - This factory can't satisfy the capability needs of the request
+            // - The concrete implementation of the factory rejects the request
+            && ((n.score > mScore && n.providerId != mProviderId)
+                    || !n.request.networkCapabilities.satisfiedByNetworkCapabilities(
+                            mCapabilityFilter)
+                    || !acceptRequest(n.request, n.score));
+    }
+
+    private void evalRequests() {
+        for (int i = 0; i < mNetworkRequests.size(); i++) {
+            NetworkRequestInfo n = mNetworkRequests.valueAt(i);
+            evalRequest(n);
+        }
+    }
+
+    /**
+     * Post a command, on this NetworkFactory Handler, to re-evaluate all
+     * outstanding requests. Can be called from a factory implementation.
+     */
+    protected void reevaluateAllRequests() {
+        post(() -> {
+            evalRequests();
+        });
+    }
+
+    /**
+     * Can be called by a factory to release a request as unfulfillable: the request will be
+     * removed, and the caller will get a
+     * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function
+     * returns.
+     *
+     * Note: this should only be called by factory which KNOWS that it is the ONLY factory which
+     * is able to fulfill this request!
+     */
+    protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) {
+        post(() -> {
+            if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r);
+            ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(r);
+        });
+    }
+
+    // override to do simple mode (request independent)
+    protected void startNetwork() { }
+    protected void stopNetwork() { }
+
+    // override to do fancier stuff
+    protected void needNetworkFor(NetworkRequest networkRequest, int score) {
+        if (++mRefCount == 1) startNetwork();
+    }
+
+    protected void releaseNetworkFor(NetworkRequest networkRequest) {
+        if (--mRefCount == 0) stopNetwork();
+    }
+
+    public void setScoreFilter(int score) {
+        sendMessage(obtainMessage(CMD_SET_SCORE, score, 0));
+    }
+
+    public void setCapabilityFilter(NetworkCapabilities netCap) {
+        sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap)));
+    }
+
+    @VisibleForTesting
+    protected int getRequestCount() {
+        return mNetworkRequests.size();
+    }
+
+    /* TODO: delete when all callers have migrated to NetworkProvider IDs. */
+    public int getSerialNumber() {
+        return mProviderId;
+    }
+
+    public int getProviderId() {
+        return mProviderId;
+    }
+
+    protected void log(String s) {
+        Log.d(LOG_TAG, s);
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        pw.println(toString());
+        pw.increaseIndent();
+        for (int i = 0; i < mNetworkRequests.size(); i++) {
+            pw.println(mNetworkRequests.valueAt(i));
+        }
+        pw.decreaseIndent();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mProviderId=")
+                .append(mProviderId).append(", ScoreFilter=")
+                .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=")
+                .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount)
+                .append("}");
+        return sb.toString();
+    }
+}