Refactor GnssBatchingProvider

Bug: 77974758
Fixes: 77974758
Test: m -j ROBOTEST_FILTER=GnssBatchingProviderTest RunFrameworksServicesRoboTests

Change-Id: I907265358abdd5486dc1040c7d7bf912942bcb1d
This commit is contained in:
Yu-Han Yang
2018-03-21 12:48:36 -07:00
parent ae4518c736
commit 3557cc71ea
5 changed files with 265 additions and 98 deletions

View File

@@ -86,6 +86,7 @@ import com.android.server.location.ActivityRecognitionProxy;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceManager;
import com.android.server.location.GeofenceProxy;
import com.android.server.location.GnssBatchingProvider;
import com.android.server.location.GnssLocationProvider;
import com.android.server.location.GnssMeasurementsProvider;
import com.android.server.location.GnssNavigationMessageProvider;
@@ -244,7 +245,7 @@ public class LocationManagerService extends ILocationManager.Stub {
private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
private GnssLocationProvider.GnssBatchingProvider mGnssBatchingProvider;
private GnssBatchingProvider mGnssBatchingProvider;
private IBatchedLocationCallback mGnssBatchingCallback;
private LinkedCallback mGnssBatchingDeathCallback;
private boolean mGnssBatchingInProgress = false;
@@ -1173,7 +1174,7 @@ public class LocationManagerService extends ILocationManager.Stub {
"Location Hardware permission not granted to access hardware batching");
if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
return mGnssBatchingProvider.getSize();
return mGnssBatchingProvider.getBatchSize();
} else {
return 0;
}

View File

@@ -0,0 +1,145 @@
package com.android.server.location;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
/**
* Manages GNSS Batching operations.
*
* <p>This class is not thread safe (It's client's responsibility to make sure calls happen on
* the same thread).
*/
public class GnssBatchingProvider {
private static final String TAG = "GnssBatchingProvider";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final GnssBatchingProviderNative mNative;
private boolean mEnabled;
private boolean mStarted;
private long mPeriodNanos;
private boolean mWakeOnFifoFull;
GnssBatchingProvider() {
this(new GnssBatchingProviderNative());
}
@VisibleForTesting
GnssBatchingProvider(GnssBatchingProviderNative gnssBatchingProviderNative) {
mNative = gnssBatchingProviderNative;
}
/**
* Returns the GNSS batching size
*/
public int getBatchSize() {
return mNative.getBatchSize();
}
/** Enable GNSS batching. */
public void enable() {
mEnabled = mNative.initBatching();
if (!mEnabled) {
Log.e(TAG, "Failed to initialize GNSS batching");
}
}
/**
* Starts the hardware batching operation
*/
public boolean start(long periodNanos, boolean wakeOnFifoFull) {
if (!mEnabled) {
throw new IllegalStateException();
}
if (periodNanos <= 0) {
Log.e(TAG, "Invalid periodNanos " + periodNanos +
" in batching request, not started");
return false;
}
mStarted = mNative.startBatch(periodNanos, wakeOnFifoFull);
if (mStarted) {
mPeriodNanos = periodNanos;
mWakeOnFifoFull = wakeOnFifoFull;
}
return mStarted;
}
/**
* Forces a flush of existing locations from the hardware batching
*/
public void flush() {
if (!mStarted) {
Log.w(TAG, "Cannot flush since GNSS batching has not started.");
return;
}
mNative.flushBatch();
}
/**
* Stops the batching operation
*/
public boolean stop() {
boolean stopped = mNative.stopBatch();
if (stopped) {
mStarted = false;
}
return stopped;
}
/** Disable GNSS batching. */
public void disable() {
stop();
mNative.cleanupBatching();
mEnabled = false;
}
// TODO(b/37460011): Use this with death recovery logic.
void resumeIfStarted() {
if (DEBUG) {
Log.d(TAG, "resumeIfStarted");
}
if (mStarted) {
mNative.startBatch(mPeriodNanos, mWakeOnFifoFull);
}
}
@VisibleForTesting
static class GnssBatchingProviderNative {
public int getBatchSize() {
return native_get_batch_size();
}
public boolean startBatch(long periodNanos, boolean wakeOnFifoFull) {
return native_start_batch(periodNanos, wakeOnFifoFull);
}
public void flushBatch() {
native_flush_batch();
}
public boolean stopBatch() {
return native_stop_batch();
}
public boolean initBatching() {
return native_init_batching();
}
public void cleanupBatching() {
native_cleanup_batching();
}
}
private static native int native_get_batch_size();
private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
private static native void native_flush_batch();
private static native boolean native_stop_batch();
private static native boolean native_init_batching();
private static native void native_cleanup_batching();
}

View File

@@ -420,6 +420,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
private final NtpTimeHelper mNtpTimeHelper;
private final GnssBatchingProvider mGnssBatchingProvider;
// Handler for processing events
private Handler mHandler;
@@ -887,6 +888,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
mGnssSatelliteBlacklistHelper = new GnssSatelliteBlacklistHelper(mContext,
looper, this);
mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
mGnssBatchingProvider = new GnssBatchingProvider();
}
/**
@@ -1273,7 +1275,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
mGnssMeasurementsProvider.onGpsEnabledChanged();
mGnssNavigationMessageProvider.onGpsEnabledChanged();
enableBatching();
mGnssBatchingProvider.enable();
} else {
synchronized (mLock) {
mEnabled = false;
@@ -1305,7 +1307,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
mAlarmManager.cancel(mWakeupIntent);
mAlarmManager.cancel(mTimeoutIntent);
disableBatching();
mGnssBatchingProvider.disable();
// do this before releasing wakelock
native_cleanup();
@@ -2007,58 +2009,11 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
};
}
public interface GnssBatchingProvider {
/**
* Returns the GNSS batching size
*/
int getSize();
/**
* Starts the hardware batching operation
*/
boolean start(long periodNanos, boolean wakeOnFifoFull);
/**
* Forces a flush of existing locations from the hardware batching
*/
void flush();
/**
* Stops the batching operation
*/
boolean stop();
}
/**
* @hide
*/
public GnssBatchingProvider getGnssBatchingProvider() {
return new GnssBatchingProvider() {
@Override
public int getSize() {
return native_get_batch_size();
}
@Override
public boolean start(long periodNanos, boolean wakeOnFifoFull) {
if (periodNanos <= 0) {
Log.e(TAG, "Invalid periodNanos " + periodNanos +
"in batching request, not started");
return false;
}
return native_start_batch(periodNanos, wakeOnFifoFull);
}
@Override
public void flush() {
native_flush_batch();
}
@Override
public boolean stop() {
return native_stop_batch();
}
};
return mGnssBatchingProvider;
}
public interface GnssMetricsProvider {
@@ -2080,23 +2035,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
};
}
/**
* Initialize Batching if enabled
*/
private void enableBatching() {
if (!native_init_batching()) {
Log.e(TAG, "Failed to initialize GNSS batching");
}
}
/**
* Disable batching
*/
private void disableBatching() {
native_stop_batch();
native_cleanup_batching();
}
/**
* called from native code - GNSS location batch callback
*/
@@ -2918,19 +2856,5 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
// GNSS Batching
private static native int native_get_batch_size();
private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
private static native void native_flush_batch();
private static native boolean native_stop_batch();
private static native boolean native_init_batching();
private static native void native_cleanup_batching();
}

View File

@@ -2050,7 +2050,7 @@ static jboolean android_location_GnssLocationProvider_set_satellite_blacklist(
}
static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) {
static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return 0; // batching not supported, size = 0
}
@@ -2062,7 +2062,7 @@ static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass
}
}
static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jclass) {
static jboolean android_location_GnssBatchingProvider_init_batching(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return JNI_FALSE; // batching not supported
}
@@ -2071,14 +2071,14 @@ static jboolean android_location_GnssLocationProvider_init_batching(JNIEnv*, jcl
return static_cast<jboolean>(gnssBatchingIface->init(gnssBatchingCbIface));
}
static void android_location_GnssLocationProvider_cleanup_batching(JNIEnv*, jclass) {
static void android_location_GnssBatchingProvider_cleanup_batching(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
gnssBatchingIface->cleanup();
}
static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclass,
static jboolean android_location_GnssBatchingProvider_start_batch(JNIEnv*, jclass,
jlong periodNanos, jboolean wakeOnFifoFull) {
if (gnssBatchingIface == nullptr) {
return JNI_FALSE; // batching not supported
@@ -2095,7 +2095,7 @@ static jboolean android_location_GnssLocationProvider_start_batch(JNIEnv*, jclas
return static_cast<jboolean>(gnssBatchingIface->start(options));
}
static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) {
static void android_location_GnssBatchingProvider_flush_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
@@ -2103,7 +2103,7 @@ static void android_location_GnssLocationProvider_flush_batch(JNIEnv*, jclass) {
gnssBatchingIface->flush();
}
static jboolean android_location_GnssLocationProvider_stop_batch(JNIEnv*, jclass) {
static jboolean android_location_GnssBatchingProvider_stop_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return JNI_FALSE; // batching not supported
}
@@ -2241,30 +2241,36 @@ static const JNINativeMethod sMethods[] = {
{"native_set_satellite_blacklist",
"([I[I)Z",
reinterpret_cast<void *>(android_location_GnssLocationProvider_set_satellite_blacklist)},
};
static const JNINativeMethod sMethodsBatching[] = {
/* name, signature, funcPtr */
{"native_get_batch_size",
"()I",
reinterpret_cast<void *>(android_location_GnssLocationProvider_get_batch_size)},
{"native_init_batching",
"()Z",
reinterpret_cast<void *>(android_location_GnssLocationProvider_init_batching)},
reinterpret_cast<void *>(android_location_GnssBatchingProvider_get_batch_size)},
{"native_start_batch",
"(JZ)Z",
reinterpret_cast<void *>(android_location_GnssLocationProvider_start_batch)},
reinterpret_cast<void *>(android_location_GnssBatchingProvider_start_batch)},
{"native_flush_batch",
"()V",
reinterpret_cast<void *>(android_location_GnssLocationProvider_flush_batch)},
reinterpret_cast<void *>(android_location_GnssBatchingProvider_flush_batch)},
{"native_stop_batch",
"()Z",
reinterpret_cast<void *>(android_location_GnssLocationProvider_stop_batch)},
reinterpret_cast<void *>(android_location_GnssBatchingProvider_stop_batch)},
{"native_init_batching",
"()Z",
reinterpret_cast<void *>(android_location_GnssLocationProvider_init_batching)},
reinterpret_cast<void *>(android_location_GnssBatchingProvider_init_batching)},
{"native_cleanup_batching",
"()V",
reinterpret_cast<void *>(android_location_GnssLocationProvider_cleanup_batching)},
reinterpret_cast<void *>(android_location_GnssBatchingProvider_cleanup_batching)},
};
int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
jniRegisterNativeMethods(
env,
"com/android/server/location/GnssBatchingProvider",
sMethodsBatching,
NELEM(sMethodsBatching));
return jniRegisterNativeMethods(
env,
"com/android/server/location/GnssLocationProvider",

View File

@@ -0,0 +1,91 @@
package com.android.server.location;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.platform.test.annotations.Presubmit;
import com.android.server.location.GnssBatchingProvider.GnssBatchingProviderNative;
import com.android.server.testing.FrameworkRobolectricTestRunner;
import com.android.server.testing.SystemLoaderPackages;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
/**
* Unit tests for {@link GnssBatchingProvider}.
*/
@RunWith(FrameworkRobolectricTestRunner.class)
@Config(
manifest = Config.NONE,
shadows = {
},
sdk = 27
)
@SystemLoaderPackages({"com.android.server.location"})
@Presubmit
public class GnssBatchingProviderTest {
private static final long PERIOD_NANOS = (long) 1e9;
private static final boolean WAKE_ON_FIFO_FULL = true;
private static final int BATCH_SIZE = 3;
@Mock
private GnssBatchingProviderNative mMockNative;
private GnssBatchingProvider mTestProvider;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mMockNative.initBatching()).thenReturn(true);
when(mMockNative.startBatch(anyLong(), anyBoolean())).thenReturn(true);
when(mMockNative.stopBatch()).thenReturn(true);
when(mMockNative.getBatchSize()).thenReturn(BATCH_SIZE);
mTestProvider = new GnssBatchingProvider(mMockNative);
mTestProvider.enable();
mTestProvider.start(PERIOD_NANOS, WAKE_ON_FIFO_FULL);
}
@Test
public void start_nativeStarted() {
verify(mMockNative).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL));
}
@Test
public void stop_nativeStopped() {
mTestProvider.stop();
verify(mMockNative).stopBatch();
}
@Test
public void flush_nativeFlushed() {
mTestProvider.flush();
verify(mMockNative).flushBatch();
}
@Test
public void getBatchSize_nativeGetBatchSize() {
assertThat(mTestProvider.getBatchSize()).isEqualTo(BATCH_SIZE);
}
@Test
public void started_resume_started() {
mTestProvider.resumeIfStarted();
verify(mMockNative, times(2)).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL));
}
@Test
public void stopped_resume_notStarted() {
mTestProvider.stop();
mTestProvider.resumeIfStarted();
verify(mMockNative, times(1)).startBatch(eq(PERIOD_NANOS), eq(WAKE_ON_FIFO_FULL));
}
}