Commit 66cfa4c6 authored by Steven Bingler's avatar Steven Bingler Committed by Commit Bot

Modify EnterpriseInfo to more easily support multiple consumers

In preparation for future changes, modify EnterpriseInfo to return the
results of a "ownership" request using a callback to the waiting
function. This change allows for multiple queued callback to wait on
a single async request. These changes make it simpler to add additional
consumers of the class.

The result of the computation is then cached for future use.
The lifetime of this cache is the lifetime of the application.

Bug: 1085168
Change-Id: I59c9d6f295d75492ddab762dc307fa67ecf21760
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2252739Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarWenyu Fu <wenyufu@chromium.org>
Commit-Queue: Steven Bingler <bingler@chromium.org>
Cr-Commit-Position: refs/heads/master@{#782830}
parent e91a999f
...@@ -9,26 +9,75 @@ import android.content.Context; ...@@ -9,26 +9,75 @@ import android.content.Context;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.Pair;
import org.chromium.base.Callback;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.task.AsyncTask; import org.chromium.base.task.AsyncTask;
import org.chromium.content_public.browser.BrowserStartupController; import org.chromium.base.task.TaskTraits;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
// TODO: This class needs tests. https://crbug.com/1099271
/** /**
* Provide the enterprise information for the current device. * Provide the enterprise information for the current device and profile.
* Currently only contains one function to record the histogram for "EnterpriseCheck.IsManaged".
*/ */
public final class EnterpriseInfo { public final class EnterpriseInfo {
private static final String TAG = "EnterpriseInfo";
// Only ever read/written on the UI thread.
private static OwnedState sOwnedState = null;
private static Queue<Callback<OwnedState>> sCallbackList =
new LinkedList<Callback<OwnedState>>();
private static class OwnedState {
boolean mDeviceOwned;
boolean mProfileOwned;
public OwnedState(boolean isDeviceOwned, boolean isProfileOwned) {
mDeviceOwned = isDeviceOwned;
mProfileOwned = isProfileOwned;
}
}
/**
* Records metrics regarding whether the device has a device owner or a profile owner.
*/
public static void logDeviceEnterpriseInfo() { public static void logDeviceEnterpriseInfo() {
assert BrowserStartupController.getInstance().isFullBrowserStarted(); Callback<OwnedState> callback = (result) -> {
recordManagementHistograms(result);
};
getDeviceEnterpriseInfo(callback);
}
private static void getDeviceEnterpriseInfo(Callback<OwnedState> callback) {
// AsyncTask requires being called from UI thread.
ThreadUtils.assertOnUiThread();
assert callback != null;
if (sOwnedState != null) {
callback.onResult(sOwnedState);
return;
}
sCallbackList.add(callback);
if (sCallbackList.size() > 1) {
// A pending callback is already being worked on, no need to start up a new thread.
return;
}
// This is the first request, spin up a thread.
try { try {
new AsyncTask<Pair<Boolean, Boolean>>() { new AsyncTask<OwnedState>() {
private Pair<Boolean, Boolean> calculateIsRunningOnManagedProfile(Context context) { // TODO: Unit test this function. https://crbug.com/1099262
private OwnedState calculateIsRunningOnManagedProfile(Context context) {
long startTime = SystemClock.elapsedRealtime(); long startTime = SystemClock.elapsedRealtime();
boolean hasProfileOwnerApp = false; boolean hasProfileOwnerApp = false;
boolean hasDeviceOwnerApp = false; boolean hasDeviceOwnerApp = false;
...@@ -53,28 +102,43 @@ public final class EnterpriseInfo { ...@@ -53,28 +102,43 @@ public final class EnterpriseInfo {
"EnterpriseCheck.IsRunningOnManagedProfileDuration", "EnterpriseCheck.IsRunningOnManagedProfileDuration",
endTime - startTime); endTime - startTime);
return new Pair<>(hasProfileOwnerApp, hasDeviceOwnerApp); return new OwnedState(hasDeviceOwnerApp, hasProfileOwnerApp);
} }
@Override @Override
protected Pair<Boolean, Boolean> doInBackground() { protected OwnedState doInBackground() {
Context context = ContextUtils.getApplicationContext(); Context context = ContextUtils.getApplicationContext();
return calculateIsRunningOnManagedProfile(context); return calculateIsRunningOnManagedProfile(context);
} }
@Override @Override
protected void onPostExecute(Pair<Boolean, Boolean> isManagedDevice) { protected void onPostExecute(OwnedState result) {
assert isManagedDevice != null; // This is run on the UI thread.
assert result != null;
RecordHistogram.recordBooleanHistogram( sOwnedState = result;
"EnterpriseCheck.IsManaged", isManagedDevice.first); // Notify every waiting callback.
RecordHistogram.recordBooleanHistogram( while (sCallbackList.size() > 0) {
"EnterpriseCheck.IsFullyManaged", isManagedDevice.second); sCallbackList.remove().onResult(sOwnedState);
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }
}.executeWithTaskTraits(TaskTraits.USER_VISIBLE);
} catch (RejectedExecutionException e) { } catch (RejectedExecutionException e) {
// Fail silently here since this is not a critical task. // This is an extreme edge case, but if it does happen then return null to indicate we
// couldn't execute.
Log.w(TAG, "Thread limit reached, unable to determine managed state.");
// There will only ever be a single item in the queue as we only try()/catch() on the
// first item.
sCallbackList.remove().onResult(null);
}
} }
private static void recordManagementHistograms(OwnedState state) {
if (state == null) return;
RecordHistogram.recordBooleanHistogram("EnterpriseCheck.IsManaged", state.mProfileOwned);
RecordHistogram.recordBooleanHistogram(
"EnterpriseCheck.IsFullyManaged", state.mDeviceOwned);
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment