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