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.os.UserHandle; 30 import android.util.Log; 31 import android.util.Slog; 32 33 import com.android.server.ServiceThread; 34 import com.android.server.net.BaseNetdEventCallback; 35 36 import java.util.List; 37 import 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 */ 43 final 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 // The target userId to collect network events on. The target userId will be 52 // {@link android.os.UserHandle#USER_ALL} if network events should be collected for all users. 53 private final int mTargetUserId; 54 55 private IIpConnectivityMetrics mIpConnectivityMetrics; 56 private ServiceThread mHandlerThread; 57 private NetworkLoggingHandler mNetworkLoggingHandler; 58 59 private final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() { 60 @Override 61 public void onDnsEvent(int netId, int eventType, int returnCode, String hostname, 62 String[] ipAddresses, int ipAddressesCount, long timestamp, int uid) { 63 if (!mIsLoggingEnabled.get()) { 64 return; 65 } 66 // If the network logging was enabled by the profile owner, then do not 67 // include events in the personal profile. 68 if (!shouldLogNetworkEvent(uid)) { 69 return; 70 } 71 DnsEvent dnsEvent = new DnsEvent(hostname, ipAddresses, ipAddressesCount, 72 mPm.getNameForUid(uid), timestamp); 73 sendNetworkEvent(dnsEvent); 74 } 75 76 @Override 77 public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) { 78 if (!mIsLoggingEnabled.get()) { 79 return; 80 } 81 // If the network logging was enabled by the profile owner, then do not 82 // include events in the personal profile. 83 if (!shouldLogNetworkEvent(uid)) { 84 return; 85 } 86 ConnectEvent connectEvent = new ConnectEvent(ipAddr, port, mPm.getNameForUid(uid), 87 timestamp); 88 sendNetworkEvent(connectEvent); 89 } 90 91 private void sendNetworkEvent(NetworkEvent event) { 92 Message msg = mNetworkLoggingHandler.obtainMessage( 93 NetworkLoggingHandler.LOG_NETWORK_EVENT_MSG); 94 Bundle bundle = new Bundle(); 95 bundle.putParcelable(NetworkLoggingHandler.NETWORK_EVENT_KEY, event); 96 msg.setData(bundle); 97 mNetworkLoggingHandler.sendMessage(msg); 98 } 99 100 private boolean shouldLogNetworkEvent(int uid) { 101 return mTargetUserId == UserHandle.USER_ALL 102 || mTargetUserId == UserHandle.getUserId(uid); 103 } 104 }; 105 NetworkLogger(DevicePolicyManagerService dpm, PackageManagerInternal pm, int targetUserId)106 NetworkLogger(DevicePolicyManagerService dpm, PackageManagerInternal pm, int targetUserId) { 107 mDpm = dpm; 108 mPm = pm; 109 mTargetUserId = targetUserId; 110 } 111 checkIpConnectivityMetricsService()112 private boolean checkIpConnectivityMetricsService() { 113 if (mIpConnectivityMetrics != null) { 114 return true; 115 } 116 final IIpConnectivityMetrics service = mDpm.mInjector.getIIpConnectivityMetrics(); 117 if (service == null) { 118 return false; 119 } 120 mIpConnectivityMetrics = service; 121 return true; 122 } 123 startNetworkLogging()124 boolean startNetworkLogging() { 125 Log.d(TAG, "Starting network logging."); 126 if (!checkIpConnectivityMetricsService()) { 127 // the IIpConnectivityMetrics service should have been present at this point 128 Slog.wtf(TAG, "Failed to register callback with IIpConnectivityMetrics."); 129 return false; 130 } 131 try { 132 if (mIpConnectivityMetrics.addNetdEventCallback( 133 INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY, mNetdEventCallback)) { 134 mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND, 135 /* allowIo */ false); 136 mHandlerThread.start(); 137 mNetworkLoggingHandler = new NetworkLoggingHandler(mHandlerThread.getLooper(), 138 mDpm, mTargetUserId); 139 mNetworkLoggingHandler.scheduleBatchFinalization(); 140 mIsLoggingEnabled.set(true); 141 return true; 142 } else { 143 return false; 144 } 145 } catch (RemoteException re) { 146 Slog.wtf(TAG, "Failed to make remote calls to register the callback", re); 147 return false; 148 } 149 } 150 stopNetworkLogging()151 boolean stopNetworkLogging() { 152 Log.d(TAG, "Stopping network logging"); 153 // stop the logging regardless of whether we fail to unregister listener 154 mIsLoggingEnabled.set(false); 155 discardLogs(); 156 157 try { 158 if (!checkIpConnectivityMetricsService()) { 159 // the IIpConnectivityMetrics service should have been present at this point 160 Slog.wtf(TAG, "Failed to unregister callback with IIpConnectivityMetrics."); 161 // logging is forcefully disabled even if unregistering fails 162 return true; 163 } 164 return mIpConnectivityMetrics.removeNetdEventCallback( 165 INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY); 166 } catch (RemoteException re) { 167 Slog.wtf(TAG, "Failed to make remote calls to unregister the callback", re); 168 return true; 169 } finally { 170 if (mHandlerThread != null) { 171 mHandlerThread.quitSafely(); 172 } 173 } 174 } 175 176 /** 177 * If logs are being collected, keep collecting them but stop notifying the admin that 178 * new logs are available (since they cannot be retrieved) 179 */ pause()180 void pause() { 181 if (mNetworkLoggingHandler != null) { 182 mNetworkLoggingHandler.pause(); 183 } 184 } 185 186 /** 187 * If logs are being collected, start notifying the admin when logs are ready to be 188 * collected again (if it was paused). 189 * <p>If logging is enabled and there are logs ready to be retrieved, this method will attempt 190 * to notify the admin. Therefore calling identity should be cleared before calling it 191 * (in case the method is called from a user other than the admin's user). 192 */ resume()193 void resume() { 194 if (mNetworkLoggingHandler != null) { 195 mNetworkLoggingHandler.resume(); 196 } 197 } 198 199 /** 200 * Discard all collected logs. 201 */ discardLogs()202 void discardLogs() { 203 if (mNetworkLoggingHandler != null) { 204 mNetworkLoggingHandler.discardLogs(); 205 } 206 } 207 retrieveLogs(long batchToken)208 List<NetworkEvent> retrieveLogs(long batchToken) { 209 return mNetworkLoggingHandler.retrieveFullLogBatch(batchToken); 210 } 211 forceBatchFinalization()212 long forceBatchFinalization() { 213 return mNetworkLoggingHandler.forceBatchFinalization(); 214 } 215 } 216