NetworkLogger.java revision d36dd15d9bf9f65270b9bee16d6419b96b18bd86
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.Message; 27import android.os.Process; 28import android.os.RemoteException; 29import android.util.Log; 30import android.util.Slog; 31 32import com.android.server.ServiceThread; 33 34import java.util.List; 35import java.util.concurrent.atomic.AtomicBoolean; 36 37/** 38 * A class for managing network logging. 39 * This class is not thread-safe, callers should synchronize access. 40 */ 41final class NetworkLogger { 42 43 private static final String TAG = NetworkLogger.class.getSimpleName(); 44 45 private final DevicePolicyManagerService mDpm; 46 private final PackageManagerInternal mPm; 47 private final AtomicBoolean mIsLoggingEnabled = new AtomicBoolean(false); 48 49 private IIpConnectivityMetrics mIpConnectivityMetrics; 50 private ServiceThread mHandlerThread; 51 private NetworkLoggingHandler mNetworkLoggingHandler; 52 53 private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() { 54 @Override 55 public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount, 56 long timestamp, int uid) { 57 if (!mIsLoggingEnabled.get()) { 58 return; 59 } 60 DnsEvent dnsEvent = new DnsEvent(hostname, ipAddresses, ipAddressesCount, 61 mPm.getNameForUid(uid), timestamp); 62 sendNetworkEvent(dnsEvent); 63 } 64 65 @Override 66 public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) { 67 if (!mIsLoggingEnabled.get()) { 68 return; 69 } 70 ConnectEvent connectEvent = new ConnectEvent(ipAddr, port, mPm.getNameForUid(uid), 71 timestamp); 72 sendNetworkEvent(connectEvent); 73 } 74 75 private void sendNetworkEvent(NetworkEvent event) { 76 Message msg = mNetworkLoggingHandler.obtainMessage( 77 NetworkLoggingHandler.LOG_NETWORK_EVENT_MSG); 78 Bundle bundle = new Bundle(); 79 bundle.putParcelable(NetworkLoggingHandler.NETWORK_EVENT_KEY, event); 80 msg.setData(bundle); 81 mNetworkLoggingHandler.sendMessage(msg); 82 } 83 }; 84 85 NetworkLogger(DevicePolicyManagerService dpm, PackageManagerInternal pm) { 86 mDpm = dpm; 87 mPm = pm; 88 } 89 90 private boolean checkIpConnectivityMetricsService() { 91 if (mIpConnectivityMetrics != null) { 92 return true; 93 } 94 final IIpConnectivityMetrics service = mDpm.mInjector.getIIpConnectivityMetrics(); 95 if (service == null) { 96 return false; 97 } 98 mIpConnectivityMetrics = service; 99 return true; 100 } 101 102 boolean startNetworkLogging() { 103 Log.d(TAG, "Starting network logging."); 104 if (!checkIpConnectivityMetricsService()) { 105 // the IIpConnectivityMetrics service should have been present at this point 106 Slog.wtf(TAG, "Failed to register callback with IIpConnectivityMetrics."); 107 return false; 108 } 109 try { 110 if (mIpConnectivityMetrics.registerNetdEventCallback(mNetdEventCallback)) { 111 mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, 112 /* allowIo */ false); 113 mHandlerThread.start(); 114 mNetworkLoggingHandler = new NetworkLoggingHandler(mHandlerThread.getLooper(), 115 mDpm); 116 mNetworkLoggingHandler.scheduleBatchFinalization(); 117 mIsLoggingEnabled.set(true); 118 return true; 119 } else { 120 return false; 121 } 122 } catch (RemoteException re) { 123 Slog.wtf(TAG, "Failed to make remote calls to register the callback", re); 124 return false; 125 } 126 } 127 128 boolean stopNetworkLogging() { 129 Log.d(TAG, "Stopping network logging"); 130 // stop the logging regardless of whether we fail to unregister listener 131 mIsLoggingEnabled.set(false); 132 discardLogs(); 133 134 try { 135 if (!checkIpConnectivityMetricsService()) { 136 // the IIpConnectivityMetrics service should have been present at this point 137 Slog.wtf(TAG, "Failed to unregister callback with IIpConnectivityMetrics."); 138 // logging is forcefully disabled even if unregistering fails 139 return true; 140 } 141 return mIpConnectivityMetrics.unregisterNetdEventCallback(); 142 } catch (RemoteException re) { 143 Slog.wtf(TAG, "Failed to make remote calls to unregister the callback", re); 144 return true; 145 } finally { 146 if (mHandlerThread != null) { 147 mHandlerThread.quitSafely(); 148 } 149 } 150 } 151 152 /** 153 * If logs are being collected, keep collecting them but stop notifying the device owner that 154 * new logs are available (since they cannot be retrieved) 155 */ 156 void pause() { 157 if (mNetworkLoggingHandler != null) { 158 mNetworkLoggingHandler.pause(); 159 } 160 } 161 162 /** 163 * If logs are being collected, start notifying the device owner when logs are ready to be 164 * collected again (if it was paused). 165 * <p>If logging is enabled and there are logs ready to be retrieved, this method will attempt 166 * to notify the device owner. Therefore calling identity should be cleared before calling it 167 * (in case the method is called from a user other than the DO's user). 168 */ 169 void resume() { 170 if (mNetworkLoggingHandler != null) { 171 mNetworkLoggingHandler.resume(); 172 } 173 } 174 175 /** 176 * Discard all collected logs. 177 */ 178 void discardLogs() { 179 if (mNetworkLoggingHandler != null) { 180 mNetworkLoggingHandler.discardLogs(); 181 } 182 } 183 184 List<NetworkEvent> retrieveLogs(long batchToken) { 185 return mNetworkLoggingHandler.retrieveFullLogBatch(batchToken); 186 } 187} 188