diff options
6 files changed, 244 insertions, 87 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 3b4f720c654f..3b80f83aab0d 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -11718,8 +11718,11 @@ public class DevicePolicyManager { } /** - * Called by a device owner or delegated app with {@link #DELEGATION_NETWORK_LOGGING} to - * control the network logging feature. + * Called by a device owner, profile owner of a managed profile or delegated app with + * {@link #DELEGATION_NETWORK_LOGGING} to control the network logging feature. + * + * <p> When network logging is enabled by a profile owner, the network logs will only include + * work profile network activity, not activity on the personal profile. * * <p> Network logs contain DNS lookup and connect() library call events. The following library * functions are recorded while network logging is active: @@ -11759,7 +11762,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if called by a delegated app. * @param enabled whether network logging should be enabled or not. - * @throws SecurityException if {@code admin} is not a device owner. + * @throws SecurityException if {@code admin} is not a device owner or profile owner. * @see #setAffiliationIds * @see #retrieveNetworkLogs */ @@ -11773,14 +11776,16 @@ public class DevicePolicyManager { } /** - * Return whether network logging is enabled by a device owner. + * Return whether network logging is enabled by a device owner or profile owner of + * a managed profile. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. Can only * be {@code null} if the caller is a delegated app with {@link #DELEGATION_NETWORK_LOGGING} * or has MANAGE_USERS permission. - * @return {@code true} if network logging is enabled by device owner, {@code false} otherwise. - * @throws SecurityException if {@code admin} is not a device owner and caller has - * no MANAGE_USERS permission + * @return {@code true} if network logging is enabled by device owner or profile owner, + * {@code false} otherwise. + * @throws SecurityException if {@code admin} is not a device owner or profile owner and + * caller has no MANAGE_USERS permission */ public boolean isNetworkLoggingEnabled(@Nullable ComponentName admin) { throwIfParentInstance("isNetworkLoggingEnabled"); @@ -11792,9 +11797,14 @@ public class DevicePolicyManager { } /** - * Called by device owner or delegated app with {@link #DELEGATION_NETWORK_LOGGING} to retrieve - * the most recent batch of network logging events. - * A device owner has to provide a batchToken provided as part of + * Called by device owner, profile owner of a managed profile or delegated app with + * {@link #DELEGATION_NETWORK_LOGGING} to retrieve the most recent batch of + * network logging events. + * + * <p> When network logging is enabled by a profile owner, the network logs will only include + * work profile network activity, not activity on the personal profile. + * + * A device owner or profile owner has to provide a batchToken provided as part of * {@link DeviceAdminReceiver#onNetworkLogsAvailable} callback. If the token doesn't match the * token of the most recent available batch of logs, {@code null} will be returned. * @@ -11806,11 +11816,11 @@ public class DevicePolicyManager { * after the device device owner has been notified via * {@link DeviceAdminReceiver#onNetworkLogsAvailable}. * - * <p>If a secondary user or profile is created, calling this method will throw a - * {@link SecurityException} until all users become affiliated again. It will also no longer be - * possible to retrieve the network logs batch with the most recent batchToken provided - * by {@link DeviceAdminReceiver#onNetworkLogsAvailable}. See - * {@link DevicePolicyManager#setAffiliationIds}. + * <p>If the caller is not a profile owner and a secondary user or profile is created, calling + * this method will throw a {@link SecurityException} until all users become affiliated again. + * It will also no longer be possible to retrieve the network logs batch with the most recent + * batchToken provided by {@link DeviceAdminReceiver#onNetworkLogsAvailable}. + * See {@link DevicePolicyManager#setAffiliationIds}. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or * {@code null} if called by a delegated app. @@ -11818,8 +11828,9 @@ public class DevicePolicyManager { * @return A new batch of network logs which is a list of {@link NetworkEvent}. Returns * {@code null} if the batch represented by batchToken is no longer available or if * logging is disabled. - * @throws SecurityException if {@code admin} is not a device owner, or there is at least one - * profile or secondary user that is not affiliated with the device. + * @throws SecurityException if {@code admin} is not a device owner, profile owner or if the + * {@code admin} is not a profile owner and there is at least one profile or secondary user + * that is not affiliated with the device. * @see #setAffiliationIds * @see DeviceAdminReceiver#onNetworkLogsAvailable */ @@ -11938,11 +11949,12 @@ public class DevicePolicyManager { } /** - * Called by the system to get the time at which the device owner last retrieved network logging - * events. + * Called by the system to get the time at which the device owner or profile owner of a + * managed profile last retrieved network logging events. * - * @return the time at which the device owner most recently retrieved network logging events, in - * milliseconds since epoch; -1 if network logging events were never retrieved. + * @return the time at which the device owner or profile owner most recently retrieved network + * logging events, in milliseconds since epoch; -1 if network logging events were + * never retrieved. * @throws SecurityException if the caller is not the device owner, does not hold the * MANAGE_USERS permission and is not the system. * diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 9a692be7f959..498ee38d442a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -781,8 +781,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * however it's too early in the boot process to register with IIpConnectivityMetrics * to listen for events. */ - if (Intent.ACTION_USER_STARTED.equals(action) - && userHandle == mOwners.getDeviceOwnerUserId()) { + if (Intent.ACTION_USER_STARTED.equals(action) && userHandle == UserHandle.USER_SYSTEM) { synchronized (getLockObject()) { if (isNetworkLoggingEnabledInternalLocked()) { setNetworkLoggingActiveInternal(true); @@ -7527,6 +7526,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { sendActiveAdminCommand(action, extras, deviceOwnerUserId, receiverComponent); } + void sendDeviceOwnerOrProfileOwnerCommand(String action, Bundle extras, int userId) { + if (userId == UserHandle.USER_ALL) { + userId = UserHandle.USER_SYSTEM; + } + ComponentName receiverComponent = null; + if (action.equals(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE)) { + receiverComponent = resolveDelegateReceiver(DELEGATION_NETWORK_LOGGING, action, userId); + } + if (receiverComponent == null) { + receiverComponent = getOwnerComponent(userId); + } + sendActiveAdminCommand(action, extras, userId, receiverComponent); + } + private void sendProfileOwnerCommand(String action, Bundle extras, @UserIdInt int userId) { sendActiveAdminCommand(action, extras, userId, mOwners.getProfileOwnerComponent(userId)); @@ -8351,6 +8364,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { deleteTransferOwnershipBundleLocked(userId); toggleBackupServiceActive(userId, true); applyManagedProfileRestrictionIfDeviceOwnerLocked(); + setNetworkLoggingActiveInternal(false); } @Override @@ -14131,7 +14145,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return; } final CallerIdentity caller = getCallerIdentity(admin, packageName); - Preconditions.checkCallAuthorization((caller.hasAdminComponent() && isDeviceOwner(caller)) + Preconditions.checkCallAuthorization((caller.hasAdminComponent() + && (isDeviceOwner(caller) + || (isProfileOwner(caller) && isManagedProfile(caller.getUserId())))) || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING))); synchronized (getLockObject()) { @@ -14139,11 +14155,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // already in the requested state return; } - ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); - deviceOwner.isNetworkLoggingEnabled = enabled; + final ActiveAdmin activeAdmin = getDeviceOrProfileOwnerAdminLocked(caller.getUserId()); + activeAdmin.isNetworkLoggingEnabled = enabled; if (!enabled) { - deviceOwner.numNetworkLoggingNotifications = 0; - deviceOwner.lastNetworkLoggingNotificationTimeMs = 0; + activeAdmin.numNetworkLoggingNotifications = 0; + activeAdmin.lastNetworkLoggingNotificationTimeMs = 0; } saveSettingsLocked(caller.getUserId()); setNetworkLoggingActiveInternal(enabled); @@ -14161,7 +14177,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { mInjector.binderWithCleanCallingIdentity(() -> { if (active) { - mNetworkLogger = new NetworkLogger(this, mInjector.getPackageManagerInternal()); + if (mNetworkLogger == null) { + final int affectedUserId = getNetworkLoggingAffectedUser(); + mNetworkLogger = new NetworkLogger(this, + mInjector.getPackageManagerInternal(), + affectedUserId == UserHandle.USER_SYSTEM + ? UserHandle.USER_ALL : affectedUserId); + } if (!mNetworkLogger.startNetworkLogging()) { mNetworkLogger = null; Slog.wtf(LOG_TAG, "Network logging could not be started due to the logging" @@ -14181,6 +14203,25 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + private @UserIdInt int getNetworkLoggingAffectedUser() { + synchronized (getLockObject()) { + if (mOwners.hasDeviceOwner()) { + return mOwners.getDeviceOwnerUserId(); + } else { + return mInjector.binderWithCleanCallingIdentity( + () -> getManagedUserId(UserHandle.USER_SYSTEM)); + } + } + } + + private ActiveAdmin getNetworkLoggingControllingAdminLocked() { + int affectedUserId = getNetworkLoggingAffectedUser(); + if (affectedUserId < 0) { + return null; + } + return getDeviceOrProfileOwnerAdminLocked(affectedUserId); + } + @Override public long forceNetworkLogs() { Preconditions.checkCallAuthorization(isAdb(getCallerIdentity()), @@ -14201,10 +14242,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @GuardedBy("getLockObject()") private void maybePauseDeviceWideLoggingLocked() { if (!areAllUsersAffiliatedWithDeviceLocked()) { - Slog.i(LOG_TAG, "There are unaffiliated users, network logging will be " - + "paused if enabled."); - if (mNetworkLogger != null) { - mNetworkLogger.pause(); + if (mOwners.hasDeviceOwner()) { + Slog.i(LOG_TAG, "There are unaffiliated users, network logging will be " + + "paused if enabled."); + if (mNetworkLogger != null) { + mNetworkLogger.pause(); + } } if (!isOrganizationOwnedDeviceWithManagedProfile()) { Slog.i(LOG_TAG, "Not org-owned managed profile device, security logging will be " @@ -14223,7 +14266,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (allUsersAffiliated || orgOwnedProfileDevice) { mSecurityLogMonitor.resume(); } - if (allUsersAffiliated) { + // If there is no device owner, then per-user network logging may be enabled for the + // managed profile. In which case, all users do not need to be affiliated. + if (allUsersAffiliated || !mOwners.hasDeviceOwner()) { if (mNetworkLogger != null) { mNetworkLogger.resume(); } @@ -14250,7 +14295,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return false; } final CallerIdentity caller = getCallerIdentity(admin, packageName); - Preconditions.checkCallAuthorization((caller.hasAdminComponent() && isDeviceOwner(caller)) + Preconditions.checkCallAuthorization((caller.hasAdminComponent() + && (isDeviceOwner(caller) + || (isProfileOwner(caller) && isManagedProfile(caller.getUserId())))) || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING)) || hasCallingOrSelfPermission(permission.MANAGE_USERS)); @@ -14260,8 +14307,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private boolean isNetworkLoggingEnabledInternalLocked() { - ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); - return (deviceOwner != null) && deviceOwner.isNetworkLoggingEnabled; + ActiveAdmin activeAdmin = getNetworkLoggingControllingAdminLocked(); + return (activeAdmin != null) && activeAdmin.isNetworkLoggingEnabled; } /* @@ -14278,9 +14325,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return null; } final CallerIdentity caller = getCallerIdentity(admin, packageName); - Preconditions.checkCallAuthorization((caller.hasAdminComponent() && isDeviceOwner(caller)) + Preconditions.checkCallAuthorization((caller.hasAdminComponent() + && (isDeviceOwner(caller) + || (isProfileOwner(caller) && isManagedProfile(caller.getUserId())))) || (caller.hasPackage() && isCallerDelegate(caller, DELEGATION_NETWORK_LOGGING))); - checkAllUsersAreAffiliatedWithDevice(); + if (mOwners.hasDeviceOwner()) { + checkAllUsersAreAffiliatedWithDevice(); + } synchronized (getLockObject()) { if (mNetworkLogger == null || !isNetworkLoggingEnabledInternalLocked()) { @@ -14293,34 +14344,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .write(); final long currentTime = System.currentTimeMillis(); - DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM); + DevicePolicyData policyData = getUserData(caller.getUserId()); if (currentTime > policyData.mLastNetworkLogsRetrievalTime) { policyData.mLastNetworkLogsRetrievalTime = currentTime; - saveSettingsLocked(UserHandle.USER_SYSTEM); + saveSettingsLocked(caller.getUserId()); } return mNetworkLogger.retrieveLogs(batchToken); } } private void sendNetworkLoggingNotificationLocked() { - final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); - if (deviceOwner == null || !deviceOwner.isNetworkLoggingEnabled) { + ensureLocked(); + final ActiveAdmin activeAdmin = getNetworkLoggingControllingAdminLocked(); + if (activeAdmin == null || !activeAdmin.isNetworkLoggingEnabled) { return; } - if (deviceOwner.numNetworkLoggingNotifications >= - ActiveAdmin.DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN) { + if (activeAdmin.numNetworkLoggingNotifications + >= ActiveAdmin.DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN) { return; } final long now = System.currentTimeMillis(); - if (now - deviceOwner.lastNetworkLoggingNotificationTimeMs < MS_PER_DAY) { + if (now - activeAdmin.lastNetworkLoggingNotificationTimeMs < MS_PER_DAY) { return; } - deviceOwner.numNetworkLoggingNotifications++; - if (deviceOwner.numNetworkLoggingNotifications + activeAdmin.numNetworkLoggingNotifications++; + if (activeAdmin.numNetworkLoggingNotifications >= ActiveAdmin.DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN) { - deviceOwner.lastNetworkLoggingNotificationTimeMs = 0; + activeAdmin.lastNetworkLoggingNotificationTimeMs = 0; } else { - deviceOwner.lastNetworkLoggingNotificationTimeMs = now; + activeAdmin.lastNetworkLoggingNotificationTimeMs = now; } final PackageManagerInternal pm = mInjector.getPackageManagerInternal(); final Intent intent = new Intent(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG); @@ -14340,7 +14392,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .bigText(mContext.getString(R.string.network_logging_notification_text))) .build(); mInjector.getNotificationManager().notify(SystemMessage.NOTE_NETWORK_LOGGING, notification); - saveSettingsLocked(mOwners.getDeviceOwnerUserId()); + saveSettingsLocked(activeAdmin.getUserHandle().getIdentifier()); } /** @@ -14404,8 +14456,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public long getLastNetworkLogRetrievalTime() { final CallerIdentity caller = getCallerIdentity(); - Preconditions.checkCallAuthorization(isDeviceOwner(caller) || canManageUsers(caller)); - return getUserData(UserHandle.USER_SYSTEM).mLastNetworkLogsRetrievalTime; + + Preconditions.checkCallAuthorization(isDeviceOwner(caller) + || (isProfileOwner(caller) && isManagedProfile(caller.getUserId())) + || canManageUsers(caller)); + final int affectedUserId = getNetworkLoggingAffectedUser(); + return affectedUserId >= 0 ? getUserData(affectedUserId).mLastNetworkLogsRetrievalTime : -1; } @Override diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java index e9b2d7f56108..8843a5d5306e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java @@ -26,6 +26,7 @@ import android.os.Bundle; import android.os.Message; import android.os.Process; import android.os.RemoteException; +import android.os.UserHandle; import android.util.Log; import android.util.Slog; @@ -47,6 +48,10 @@ final class NetworkLogger { private final PackageManagerInternal mPm; private final AtomicBoolean mIsLoggingEnabled = new AtomicBoolean(false); + // The target userId to collect network events on. The target userId will be + // {@link android.os.UserHandle#USER_ALL} if network events should be collected for all users. + private final int mTargetUserId; + private IIpConnectivityMetrics mIpConnectivityMetrics; private ServiceThread mHandlerThread; private NetworkLoggingHandler mNetworkLoggingHandler; @@ -58,6 +63,11 @@ final class NetworkLogger { if (!mIsLoggingEnabled.get()) { return; } + // If the network logging was enabled by the profile owner, then do not + // include events in the personal profile. + if (!shouldLogNetworkEvent(uid)) { + return; + } DnsEvent dnsEvent = new DnsEvent(hostname, ipAddresses, ipAddressesCount, mPm.getNameForUid(uid), timestamp); sendNetworkEvent(dnsEvent); @@ -68,6 +78,11 @@ final class NetworkLogger { if (!mIsLoggingEnabled.get()) { return; } + // If the network logging was enabled by the profile owner, then do not + // include events in the personal profile. + if (!shouldLogNetworkEvent(uid)) { + return; + } ConnectEvent connectEvent = new ConnectEvent(ipAddr, port, mPm.getNameForUid(uid), timestamp); sendNetworkEvent(connectEvent); @@ -81,11 +96,17 @@ final class NetworkLogger { msg.setData(bundle); mNetworkLoggingHandler.sendMessage(msg); } + + private boolean shouldLogNetworkEvent(int uid) { + return mTargetUserId == UserHandle.USER_ALL + || mTargetUserId == UserHandle.getUserId(uid); + } }; - NetworkLogger(DevicePolicyManagerService dpm, PackageManagerInternal pm) { + NetworkLogger(DevicePolicyManagerService dpm, PackageManagerInternal pm, int targetUserId) { mDpm = dpm; mPm = pm; + mTargetUserId = targetUserId; } private boolean checkIpConnectivityMetricsService() { @@ -114,7 +135,7 @@ final class NetworkLogger { /* allowIo */ false); mHandlerThread.start(); mNetworkLoggingHandler = new NetworkLoggingHandler(mHandlerThread.getLooper(), - mDpm); + mDpm, mTargetUserId); mNetworkLoggingHandler.scheduleBatchFinalization(); mIsLoggingEnabled.set(true); return true; @@ -153,7 +174,7 @@ final class NetworkLogger { } /** - * If logs are being collected, keep collecting them but stop notifying the device owner that + * If logs are being collected, keep collecting them but stop notifying the admin that * new logs are available (since they cannot be retrieved) */ void pause() { @@ -163,11 +184,11 @@ final class NetworkLogger { } /** - * If logs are being collected, start notifying the device owner when logs are ready to be + * If logs are being collected, start notifying the admin when logs are ready to be * collected again (if it was paused). * <p>If logging is enabled and there are logs ready to be retrieved, this method will attempt - * to notify the device owner. Therefore calling identity should be cleared before calling it - * (in case the method is called from a user other than the DO's user). + * to notify the admin. Therefore calling identity should be cleared before calling it + * (in case the method is called from a user other than the admin's user). */ void resume() { if (mNetworkLoggingHandler != null) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java index 0a7070ffe4f6..84e89a08e1f4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLoggingHandler.java @@ -50,7 +50,7 @@ final class NetworkLoggingHandler extends Handler { private static final int MAX_EVENTS_PER_BATCH = 1200; /** - * Maximum number of batches to store in memory. If more batches are generated and the DO + * Maximum number of batches to store in memory. If more batches are generated and the admin * doesn't fetch them, we will discard the oldest one. */ private static final int MAX_BATCHES = 5; @@ -74,6 +74,7 @@ final class NetworkLoggingHandler extends Handler { private final AlarmManager mAlarmManager; private long mId; + private int mTargetUserId; private final OnAlarmListener mBatchTimeoutAlarmListener = new OnAlarmListener() { @Override @@ -82,10 +83,10 @@ final class NetworkLoggingHandler extends Handler { + mNetworkEvents.size() + " pending events."); Bundle notificationExtras = null; synchronized (NetworkLoggingHandler.this) { - notificationExtras = finalizeBatchAndBuildDeviceOwnerMessageLocked(); + notificationExtras = finalizeBatchAndBuildAdminMessageLocked(); } if (notificationExtras != null) { - notifyDeviceOwner(notificationExtras); + notifyDeviceOwnerOrProfileOwner(notificationExtras); } } }; @@ -98,8 +99,8 @@ final class NetworkLoggingHandler extends Handler { private ArrayList<NetworkEvent> mNetworkEvents = new ArrayList<>(); /** - * Up to {@code MAX_BATCHES} finalized batches of logs ready to be retrieved by the DO. Already - * retrieved batches are discarded after {@code RETRIEVED_BATCH_DISCARD_DELAY_MS}. + * Up to {@code MAX_BATCHES} finalized batches of logs ready to be retrieved by the admin. + * Already retrieved batches are discarded after {@code RETRIEVED_BATCH_DISCARD_DELAY_MS}. */ @GuardedBy("this") private final LongSparseArray<ArrayList<NetworkEvent>> mBatches = @@ -115,16 +116,18 @@ final class NetworkLoggingHandler extends Handler { @GuardedBy("this") private long mLastRetrievedBatchToken; - NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm) { - this(looper, dpm, 0 /* event id */); + NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm, int targetUserId) { + this(looper, dpm, 0 /* event id */, targetUserId); } @VisibleForTesting - NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm, long id) { + NetworkLoggingHandler(Looper looper, DevicePolicyManagerService dpm, long id, + int targetUserId) { super(looper); this.mDpm = dpm; this.mAlarmManager = mDpm.mInjector.getAlarmManager(); this.mId = id; + this.mTargetUserId = targetUserId; } @Override @@ -137,11 +140,11 @@ final class NetworkLoggingHandler extends Handler { synchronized (NetworkLoggingHandler.this) { mNetworkEvents.add(networkEvent); if (mNetworkEvents.size() >= MAX_EVENTS_PER_BATCH) { - notificationExtras = finalizeBatchAndBuildDeviceOwnerMessageLocked(); + notificationExtras = finalizeBatchAndBuildAdminMessageLocked(); } } if (notificationExtras != null) { - notifyDeviceOwner(notificationExtras); + notifyDeviceOwnerOrProfileOwner(notificationExtras); } } break; @@ -176,10 +179,10 @@ final class NetworkLoggingHandler extends Handler { if (toWaitNanos > 0) { return NANOSECONDS.toMillis(toWaitNanos) + 1; // Round up. } - notificationExtras = finalizeBatchAndBuildDeviceOwnerMessageLocked(); + notificationExtras = finalizeBatchAndBuildAdminMessageLocked(); } if (notificationExtras != null) { - notifyDeviceOwner(notificationExtras); + notifyDeviceOwnerOrProfileOwner(notificationExtras); } return 0; } @@ -201,14 +204,15 @@ final class NetworkLoggingHandler extends Handler { + ", LastRetrievedBatch=" + mLastRetrievedBatchToken); mPaused = false; - // If there is a batch ready that the device owner hasn't been notified about, do it now. + // If there is a batch ready that the device owner or profile owner hasn't been + // notified about, do it now. if (mBatches.size() > 0 && mLastRetrievedBatchToken != mCurrentBatchToken) { scheduleBatchFinalization(); - notificationExtras = buildDeviceOwnerMessageLocked(); + notificationExtras = buildAdminMessageLocked(); } } if (notificationExtras != null) { - notifyDeviceOwner(notificationExtras); + notifyDeviceOwnerOrProfileOwner(notificationExtras); } } @@ -219,8 +223,8 @@ final class NetworkLoggingHandler extends Handler { } @GuardedBy("this") - /** @returns extras if a message should be sent to the device owner */ - private Bundle finalizeBatchAndBuildDeviceOwnerMessageLocked() { + /** @return extras if a message should be sent to the device owner or profile owner */ + private Bundle finalizeBatchAndBuildAdminMessageLocked() { mLastFinalizationNanos = System.nanoTime(); Bundle notificationExtras = null; if (mNetworkEvents.size() > 0) { @@ -243,10 +247,10 @@ final class NetworkLoggingHandler extends Handler { mBatches.append(mCurrentBatchToken, mNetworkEvents); mNetworkEvents = new ArrayList<>(); if (!mPaused) { - notificationExtras = buildDeviceOwnerMessageLocked(); + notificationExtras = buildAdminMessageLocked(); } } else { - // Don't notify the DO, since there are no events; DPC can still retrieve + // Don't notify the admin, since there are no events; DPC can still retrieve // the last full batch if not paused. Slog.d(TAG, "Was about to finalize the batch, but there were no events to send to" + " the DPC, the batchToken of last available batch: " + mCurrentBatchToken); @@ -257,9 +261,9 @@ final class NetworkLoggingHandler extends Handler { } @GuardedBy("this") - /** Build extras notification to the DO. Should only be called when there + /** Build extras notification to the admin. Should only be called when there is a batch available. */ - private Bundle buildDeviceOwnerMessageLocked() { + private Bundle buildAdminMessageLocked() { final Bundle extras = new Bundle(); final int lastBatchSize = mBatches.valueAt(mBatches.size() - 1).size(); extras.putLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, mCurrentBatchToken); @@ -267,16 +271,18 @@ final class NetworkLoggingHandler extends Handler { return extras; } - /** Sends a notification to the DO. Should not hold locks as DevicePolicyManagerService may - call into NetworkLoggingHandler. */ - private void notifyDeviceOwner(Bundle extras) { - Slog.d(TAG, "Sending network logging batch broadcast to device owner, batchToken: " - + extras.getLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, -1)); + /** Sends a notification to the device owner or profile owner. Should not hold locks as + DevicePolicyManagerService may call into NetworkLoggingHandler. */ + private void notifyDeviceOwnerOrProfileOwner(Bundle extras) { if (Thread.holdsLock(this)) { Slog.wtfStack(TAG, "Shouldn't be called with NetworkLoggingHandler lock held"); return; } - mDpm.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, extras); + Slog.d(TAG, "Sending network logging batch broadcast to device owner or profile owner, " + + "batchToken: " + + extras.getLong(DeviceAdminReceiver.EXTRA_NETWORK_LOGS_TOKEN, -1)); + mDpm.sendDeviceOwnerOrProfileOwnerCommand(DeviceAdminReceiver.ACTION_NETWORK_LOGS_AVAILABLE, + extras, mTargetUserId); } synchronized List<NetworkEvent> retrieveFullLogBatch(final long batchToken) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 7597cbf322f5..4002f5b4939e 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -4329,6 +4329,68 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + public void testSetNetworkLoggingEnabled_asPo() throws Exception { + final int managedProfileUserId = CALLER_USER_HANDLE; + final int managedProfileAdminUid = + UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID); + mContext.binder.callingUid = managedProfileAdminUid; + mContext.applicationInfo = new ApplicationInfo(); + mContext.packageName = admin1.getPackageName(); + addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.S); + when(getServices().iipConnectivityMetrics + .addNetdEventCallback(anyInt(), anyObject())).thenReturn(true); + + // Check no logs have been retrieved so far. + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1); + + // Enable network logging + dpm.setNetworkLoggingEnabled(admin1, true); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1); + + // Retrieve the network logs and verify timestamp has been updated. + final long beforeRetrieval = System.currentTimeMillis(); + + dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); + + final long networkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime(); + final long afterRetrieval = System.currentTimeMillis(); + assertThat(networkLogRetrievalTime >= beforeRetrieval).isTrue(); + assertThat(networkLogRetrievalTime <= afterRetrieval).isTrue(); + } + + @Test + public void testSetNetworkLoggingEnabled_asPoOfOrgOwnedDevice() throws Exception { + // Setup profile owner on organization-owned device + final int MANAGED_PROFILE_ADMIN_UID = + UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID); + addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); + configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); + + mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; + mContext.packageName = admin1.getPackageName(); + mContext.applicationInfo = new ApplicationInfo(); + when(getServices().iipConnectivityMetrics + .addNetdEventCallback(anyInt(), anyObject())).thenReturn(true); + + // Check no logs have been retrieved so far. + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1); + + // Enable network logging + dpm.setNetworkLoggingEnabled(admin1, true); + assertThat(dpm.getLastNetworkLogRetrievalTime()).isEqualTo(-1); + + // Retrieve the network logs and verify timestamp has been updated. + final long beforeRetrieval = System.currentTimeMillis(); + + dpm.retrieveNetworkLogs(admin1, 0 /* batchToken */); + + final long networkLogRetrievalTime = dpm.getLastNetworkLogRetrievalTime(); + final long afterRetrieval = System.currentTimeMillis(); + assertThat(networkLogRetrievalTime >= beforeRetrieval).isTrue(); + assertThat(networkLogRetrievalTime <= afterRetrieval).isTrue(); + } + + @Test public void testGetBindDeviceAdminTargetUsers() throws Exception { mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java index 7506dd45ad82..743b25f5c2b4 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/NetworkEventTest.java @@ -125,7 +125,7 @@ public class NetworkEventTest extends DpmTestBase { private List<NetworkEvent> fillHandlerWithFullBatchOfEvents(long startingId) throws Exception { // GIVEN a handler with events NetworkLoggingHandler handler = new NetworkLoggingHandler(new TestLooper().getLooper(), - mDpmTestable, startingId); + mDpmTestable, startingId, DpmMockContext.CALLER_USER_HANDLE); // GIVEN network events are sent to the handler. for (int i = 0; i < MAX_EVENTS_PER_BATCH; i++) { ConnectEvent event = new ConnectEvent("some_ip_address", 800, "com.google.foo", |