NetworkLogger.java revision e4dfd2d0028ff1c7088ec58a4d3eaf8f222311e6
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.devicepolicy;
18
19import android.app.admin.ConnectEvent;
20import android.app.admin.DnsEvent;
21import android.app.admin.NetworkEvent;
22import android.content.pm.PackageManagerInternal;
23import android.net.IIpConnectivityMetrics;
24import android.net.INetdEventCallback;
25import android.os.Bundle;
26import android.os.Handler;
27import android.os.Message;
28import android.os.Process;
29import android.os.RemoteException;
30import android.util.Log;
31import android.util.Slog;
32
33import com.android.server.ServiceThread;
34
35import java.util.ArrayList;
36import java.util.List;
37import java.util.concurrent.atomic.AtomicBoolean;
38
39/**
40 * A class for managing network logging.
41 * This class is not thread-safe, callers should synchronize access.
42 */
43final class NetworkLogger {
44
45    private static final String TAG = NetworkLogger.class.getSimpleName();
46
47    private final DevicePolicyManagerService mDpm;
48    private final PackageManagerInternal mPm;
49    private final AtomicBoolean mIsLoggingEnabled = new AtomicBoolean(false);
50
51    private IIpConnectivityMetrics mIpConnectivityMetrics;
52    private ServiceThread mHandlerThread;
53    private NetworkLoggingHandler mNetworkLoggingHandler;
54
55    private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
56        @Override
57        public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
58                long timestamp, int uid) {
59            if (!mIsLoggingEnabled.get()) {
60                return;
61            }
62            DnsEvent dnsEvent = new DnsEvent(hostname, ipAddresses, ipAddressesCount,
63                    mPm.getNameForUid(uid), timestamp);
64            sendNetworkEvent(dnsEvent);
65        }
66
67        @Override
68        public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) {
69            if (!mIsLoggingEnabled.get()) {
70                return;
71            }
72            ConnectEvent connectEvent = new ConnectEvent(ipAddr, port, mPm.getNameForUid(uid),
73                    timestamp);
74            sendNetworkEvent(connectEvent);
75        }
76
77        private void sendNetworkEvent(NetworkEvent event) {
78            Message msg = mNetworkLoggingHandler.obtainMessage(
79                    NetworkLoggingHandler.LOG_NETWORK_EVENT_MSG);
80            Bundle bundle = new Bundle();
81            bundle.putParcelable(NetworkLoggingHandler.NETWORK_EVENT_KEY, event);
82            msg.setData(bundle);
83            mNetworkLoggingHandler.sendMessage(msg);
84        }
85    };
86
87    NetworkLogger(DevicePolicyManagerService dpm, PackageManagerInternal pm) {
88        mDpm = dpm;
89        mPm = pm;
90    }
91
92    private boolean checkIpConnectivityMetricsService() {
93        if (mIpConnectivityMetrics != null) {
94            return true;
95        }
96        final IIpConnectivityMetrics service = mDpm.mInjector.getIIpConnectivityMetrics();
97        if (service == null) {
98            return false;
99        }
100        mIpConnectivityMetrics = service;
101        return true;
102    }
103
104    boolean startNetworkLogging() {
105        Log.d(TAG, "Starting network logging.");
106        if (!checkIpConnectivityMetricsService()) {
107            // the IIpConnectivityMetrics service should have been present at this point
108            Slog.wtf(TAG, "Failed to register callback with IIpConnectivityMetrics.");
109            return false;
110        }
111        try {
112           if (mIpConnectivityMetrics.registerNetdEventCallback(mNetdEventCallback)) {
113                mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
114                        /* allowIo */ false);
115                mHandlerThread.start();
116                mNetworkLoggingHandler = new NetworkLoggingHandler(mHandlerThread.getLooper(),
117                        mDpm);
118                mNetworkLoggingHandler.scheduleBatchFinalization(
119                        NetworkLoggingHandler.BATCH_FINALIZATION_TIMEOUT_MS);
120                mIsLoggingEnabled.set(true);
121                return true;
122            } else {
123                return false;
124            }
125        } catch (RemoteException re) {
126            Slog.wtf(TAG, "Failed to make remote calls to register the callback", re);
127            return false;
128        }
129    }
130
131    boolean stopNetworkLogging() {
132        Log.d(TAG, "Stopping network logging");
133        // stop the logging regardless of whether we fail to unregister listener
134        mIsLoggingEnabled.set(false);
135        try {
136            if (!checkIpConnectivityMetricsService()) {
137                // the IIpConnectivityMetrics service should have been present at this point
138                Slog.wtf(TAG, "Failed to unregister callback with IIpConnectivityMetrics.");
139                // logging is forcefully disabled even if unregistering fails
140                return true;
141            }
142            return mIpConnectivityMetrics.unregisterNetdEventCallback();
143        } catch (RemoteException re) {
144            Slog.wtf(TAG, "Failed to make remote calls to unregister the callback", re);
145        } finally {
146            mHandlerThread.quitSafely();
147            return true;
148        }
149    }
150
151    List<NetworkEvent> retrieveLogs(long batchToken) {
152        return mNetworkLoggingHandler.retrieveFullLogBatch(batchToken);
153    }
154}
155