/*
 * 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 com.android.server.connectivity;

import android.content.Context;
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
import android.net.INetdEventCallback;
import android.net.ip.IpClient;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.IpConnectivityLog;
import android.os.Binder;
import android.os.Process;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.Base64;
import android.util.Log;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.RingBuffer;
import com.android.internal.util.TokenBucket;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.ToIntFunction;

/**
 * Event buffering service for core networking and connectivity metrics.
 *
 * {@hide}
 */
final public class IpConnectivityMetrics extends SystemService {
    private static final String TAG = IpConnectivityMetrics.class.getSimpleName();
    private static final boolean DBG = false;

    // The logical version numbers of ipconnectivity.proto, corresponding to the
    // "version" field of IpConnectivityLog.
    private static final int NYC      = 0;
    private static final int NYC_MR1  = 1;
    private static final int NYC_MR2  = 2;
    public static final int VERSION   = NYC_MR2;

    private static final String SERVICE_NAME = IpConnectivityLog.SERVICE_NAME;

    // Default size of the event rolling log for bug report dumps.
    private static final int DEFAULT_LOG_SIZE = 500;
    // Default size of the event buffer for metrics reporting.
    // Once the buffer is full, incoming events are dropped.
    private static final int DEFAULT_BUFFER_SIZE = 2000;
    // Maximum size of the event buffer.
    private static final int MAXIMUM_BUFFER_SIZE = DEFAULT_BUFFER_SIZE * 10;

    private static final int MAXIMUM_CONNECT_LATENCY_RECORDS = 20000;

    private static final int ERROR_RATE_LIMITED = -1;

    // Lock ensuring that concurrent manipulations of the event buffers are correct.
    // There are three concurrent operations to synchronize:
    //  - appending events to the buffer.
    //  - iterating throught the buffer.
    //  - flushing the buffer content and replacing it by a new buffer.
    private final Object mLock = new Object();

    // Implementation instance of IIpConnectivityMetrics.aidl.
    @VisibleForTesting
    public final Impl impl = new Impl();
    // Subservice listening to Netd events via INetdEventListener.aidl.
    @VisibleForTesting
    NetdEventListenerService mNetdListener;

    // Rolling log of the most recent events. This log is used for dumping
    // connectivity events in bug reports.
    @GuardedBy("mLock")
    private final RingBuffer<ConnectivityMetricsEvent> mEventLog =
            new RingBuffer(ConnectivityMetricsEvent.class, DEFAULT_LOG_SIZE);
    // Buffer of connectivity events used for metrics reporting. This buffer
    // does not rotate automatically and instead saturates when it becomes full.
    // It is flushed at metrics reporting.
    @GuardedBy("mLock")
    private ArrayList<ConnectivityMetricsEvent> mBuffer;
    // Total number of events dropped from mBuffer since last metrics reporting.
    @GuardedBy("mLock")
    private int mDropped;
    // Capacity of mBuffer
    @GuardedBy("mLock")
    private int mCapacity;
    // A list of rate limiting counters keyed by connectivity event types for
    // metrics reporting mBuffer.
    @GuardedBy("mLock")
    private final ArrayMap<Class<?>, TokenBucket> mBuckets = makeRateLimitingBuckets();

    private final ToIntFunction<Context> mCapacityGetter;

    @VisibleForTesting
    final DefaultNetworkMetrics mDefaultNetworkMetrics = new DefaultNetworkMetrics();

    public IpConnectivityMetrics(Context ctx, ToIntFunction<Context> capacityGetter) {
        super(ctx);
        mCapacityGetter = capacityGetter;
        initBuffer();
    }

    public IpConnectivityMetrics(Context ctx) {
        this(ctx, READ_BUFFER_SIZE);
    }

    @Override
    public void onStart() {
        if (DBG) Log.d(TAG, "onStart");
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            if (DBG) Log.d(TAG, "onBootPhase");
            mNetdListener = new NetdEventListenerService(getContext());

            publishBinderService(SERVICE_NAME, impl);
            publishBinderService(mNetdListener.SERVICE_NAME, mNetdListener);

            LocalServices.addService(Logger.class, new LoggerImpl());
        }
    }

    @VisibleForTesting
    public int bufferCapacity() {
        return mCapacityGetter.applyAsInt(getContext());
    }

    private void initBuffer() {
        synchronized (mLock) {
            mDropped = 0;
            mCapacity = bufferCapacity();
            mBuffer = new ArrayList<>(mCapacity);
        }
    }

    private int append(ConnectivityMetricsEvent event) {
        if (DBG) Log.d(TAG, "logEvent: " + event);
        synchronized (mLock) {
            mEventLog.append(event);
            final int left = mCapacity - mBuffer.size();
            if (event == null) {
                return left;
            }
            if (isRateLimited(event)) {
                // Do not count as a dropped event. TODO: consider adding separate counter
                return ERROR_RATE_LIMITED;
            }
            if (left == 0) {
                mDropped++;
                return 0;
            }
            mBuffer.add(event);
            return left - 1;
        }
    }

    private boolean isRateLimited(ConnectivityMetricsEvent event) {
        TokenBucket tb = mBuckets.get(event.data.getClass());
        return (tb != null) && !tb.get();
    }

    private String flushEncodedOutput() {
        final ArrayList<ConnectivityMetricsEvent> events;
        final int dropped;
        synchronized (mLock) {
            events = mBuffer;
            dropped = mDropped;
            initBuffer();
        }

        final List<IpConnectivityEvent> protoEvents = IpConnectivityEventBuilder.toProto(events);

        mDefaultNetworkMetrics.flushEvents(protoEvents);

        if (mNetdListener != null) {
            mNetdListener.flushStatistics(protoEvents);
        }

        final byte[] data;
        try {
            data = IpConnectivityEventBuilder.serialize(dropped, protoEvents);
        } catch (IOException e) {
            Log.e(TAG, "could not serialize events", e);
            return "";
        }

        return Base64.encodeToString(data, Base64.DEFAULT);
    }

    /**
     * Clear the event buffer and prints its content as a protobuf serialized byte array
     * inside a base64 encoded string.
     */
    private void cmdFlush(PrintWriter pw) {
        pw.print(flushEncodedOutput());
    }

    /**
     * Print the content of the rolling event buffer in human readable format.
     * Also print network dns/connect statistics and recent default network events.
     */
    private void cmdList(PrintWriter pw) {
        pw.println("metrics events:");
        final List<ConnectivityMetricsEvent> events = getEvents();
        for (ConnectivityMetricsEvent ev : events) {
            pw.println(ev.toString());
        }
        pw.println("");
        if (mNetdListener != null) {
            mNetdListener.list(pw);
        }
        pw.println("");
        mDefaultNetworkMetrics.listEvents(pw);
    }

    /*
     * Print the content of the rolling event buffer in text proto format.
     */
    private void cmdListAsProto(PrintWriter pw) {
        final List<ConnectivityMetricsEvent> events = getEvents();
        for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
            pw.print(ev.toString());
        }
        if (mNetdListener != null) {
            mNetdListener.listAsProtos(pw);
        }
        mDefaultNetworkMetrics.listEventsAsProto(pw);
    }

    /*
     * Return a copy of metrics events stored in buffer for metrics uploading.
     */
    private List<ConnectivityMetricsEvent> getEvents() {
        synchronized (mLock) {
            return Arrays.asList(mEventLog.toArray());
        }
    }

    public final class Impl extends IIpConnectivityMetrics.Stub {
        // Dump and flushes the metrics event buffer in base64 encoded serialized proto output.
        static final String CMD_FLUSH = "flush";
        // Dump the rolling buffer of metrics event in human readable proto text format.
        static final String CMD_PROTO = "proto";
        // Dump the rolling buffer of metrics event and pretty print events using a human readable
        // format. Also print network dns/connect statistics and default network event time series.
        static final String CMD_LIST = "list";
        // Dump all IpClient logs ("ipclient").
        static final String CMD_IPCLIENT = IpClient.DUMP_ARG;
        // By default any other argument will fall into the default case which is the equivalent
        // of calling both the "list" and "ipclient" commands. This includes most notably bug
        // reports collected by dumpsys.cpp with the "-a" argument.
        static final String CMD_DEFAULT = "";

        @Override
        public int logEvent(ConnectivityMetricsEvent event) {
            enforceConnectivityInternalPermission();
            return append(event);
        }

        @Override
        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            enforceDumpPermission();
            if (DBG) Log.d(TAG, "dumpsys " + TextUtils.join(" ", args));
            final String cmd = (args.length > 0) ? args[0] : CMD_DEFAULT;
            switch (cmd) {
                case CMD_FLUSH:
                    cmdFlush(pw);
                    return;
                case CMD_PROTO:
                    cmdListAsProto(pw);
                    return;
                case CMD_IPCLIENT: {
                    final String[] ipclientArgs = ((args != null) && (args.length > 1))
                            ? Arrays.copyOfRange(args, 1, args.length)
                            : null;
                    IpClient.dumpAllLogs(pw, ipclientArgs);
                    return;
                }
                case CMD_LIST:
                    cmdList(pw);
                    return;
                default:
                    cmdList(pw);
                    pw.println("");
                    IpClient.dumpAllLogs(pw, null);
                    return;
            }
        }

        private void enforceConnectivityInternalPermission() {
            enforcePermission(android.Manifest.permission.CONNECTIVITY_INTERNAL);
        }

        private void enforceDumpPermission() {
            enforcePermission(android.Manifest.permission.DUMP);
        }

        private void enforcePermission(String what) {
            getContext().enforceCallingOrSelfPermission(what, "IpConnectivityMetrics");
        }

        private void enforceNetdEventListeningPermission() {
            final int uid = Binder.getCallingUid();
            if (uid != Process.SYSTEM_UID) {
                throw new SecurityException(String.format("Uid %d has no permission to listen for"
                        + " netd events.", uid));
            }
        }

        @Override
        public boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
            enforceNetdEventListeningPermission();
            if (mNetdListener == null) {
                return false;
            }
            return mNetdListener.addNetdEventCallback(callerType, callback);
        }

        @Override
        public boolean removeNetdEventCallback(int callerType) {
            enforceNetdEventListeningPermission();
            if (mNetdListener == null) {
                // if the service is null, we aren't registered anyway
                return true;
            }
            return mNetdListener.removeNetdEventCallback(callerType);
        }
    };

    private static final ToIntFunction<Context> READ_BUFFER_SIZE = (ctx) -> {
        int size = Settings.Global.getInt(ctx.getContentResolver(),
                Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE, DEFAULT_BUFFER_SIZE);
        if (size <= 0) {
            return DEFAULT_BUFFER_SIZE;
        }
        return Math.min(size, MAXIMUM_BUFFER_SIZE);
    };

    private static ArrayMap<Class<?>, TokenBucket> makeRateLimitingBuckets() {
        ArrayMap<Class<?>, TokenBucket> map = new ArrayMap<>();
        // one token every minute, 50 tokens max: burst of ~50 events every hour.
        map.put(ApfProgramEvent.class, new TokenBucket((int)DateUtils.MINUTE_IN_MILLIS, 50));
        return map;
    }

    /** Direct non-Binder interface for event producer clients within the system servers. */
    public interface Logger {
        DefaultNetworkMetrics defaultNetworkMetrics();
    }

    private class LoggerImpl implements Logger {
        public DefaultNetworkMetrics defaultNetworkMetrics() {
            return mDefaultNetworkMetrics;
        }
    }
}
