summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShubham Ajmera <shubhamajmera@google.com>2016-05-13 08:34:08 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-05-13 08:34:08 +0000
commit7c116469192d5705de101bd7513a6c9ad52cbdca (patch)
tree4a900f20acaaf7aee1ec44177b31f7dc09034278
parenta40d072b792057929097e2fbadf01d341a6a5456 (diff)
parent34c10c16614ff6d4a5e2b50aeb86ed1d1fc603ec (diff)
downloadplatform_cts-7c116469192d5705de101bd7513a6c9ad52cbdca.tar.gz
platform_cts-7c116469192d5705de101bd7513a6c9ad52cbdca.tar.bz2
platform_cts-7c116469192d5705de101bd7513a6c9ad52cbdca.zip
Merge "Add tests for java.nio.channels.FileChannel lock methods"android-wear-n-preview-1android-n-preview-3
-rw-r--r--CtsTestCaseList.mk1
-rw-r--r--tests/tests/libcorefileio/AndroidManifest.xml3
-rw-r--r--tests/tests/libcorefileio/AndroidTest.xml23
-rw-r--r--tests/tests/libcorefileio/src/android/cts/FileChannelInterProcessLockTest.java551
-rw-r--r--tests/tests/libcorefileio/src/android/cts/FileChannelTryLockTest.java99
-rw-r--r--tests/tests/libcorefileio/src/android/cts/LockHoldingService.java144
6 files changed, 680 insertions, 141 deletions
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 745cd6bae6c..7a2ced28a05 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -172,6 +172,7 @@ cts_test_packages := \
CtsJniTestCases \
CtsKeystoreTestCases \
CtsLibcoreLegacy22TestCases \
+ CtsLibcoreFileIOTestCases \
CtsLocationTestCases \
CtsLocation2TestCases \
CtsMediaStressTestCases \
diff --git a/tests/tests/libcorefileio/AndroidManifest.xml b/tests/tests/libcorefileio/AndroidManifest.xml
index 4557eec457c..6eb1439b100 100644
--- a/tests/tests/libcorefileio/AndroidManifest.xml
+++ b/tests/tests/libcorefileio/AndroidManifest.xml
@@ -26,7 +26,7 @@
android:process=":lockHoldingService"
android:permission="android.permission.WRITE_EXTERNAL_STORAGE"
/>
- <receiver android:name="android.cts.FileChannelTryLockTest$IntentReceiver">
+ <receiver android:name="android.cts.FileChannelInterProcessLockTest$IntentReceiver">
<intent-filter>
<action android:name="android.cts.CtsLibcoreFileIOTestCases">
@@ -43,4 +43,3 @@
</instrumentation>
</manifest>
-
diff --git a/tests/tests/libcorefileio/AndroidTest.xml b/tests/tests/libcorefileio/AndroidTest.xml
deleted file mode 100644
index 9baa7132b72..00000000000
--- a/tests/tests/libcorefileio/AndroidTest.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for CTS Legacy Libcore test cases">
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="CtsLibcoreFileIOTestCases.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.libcorefileio.cts" />
- </test>
-</configuration> \ No newline at end of file
diff --git a/tests/tests/libcorefileio/src/android/cts/FileChannelInterProcessLockTest.java b/tests/tests/libcorefileio/src/android/cts/FileChannelInterProcessLockTest.java
new file mode 100644
index 00000000000..05894d5f1c8
--- /dev/null
+++ b/tests/tests/libcorefileio/src/android/cts/FileChannelInterProcessLockTest.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.cts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Environment;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileLock;
+import java.util.concurrent.CountDownLatch;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+@SuppressWarnings("deprecation")
+public class FileChannelInterProcessLockTest extends AndroidTestCase {
+
+ /** The directory where file locks are created */
+ final static String DIR_NAME = "CtsFileIOTest";
+
+ /** The name of the file used when acquiring a lock. */
+ final static String FILE_NAME = "file";
+
+ /** The position in the lock file used when acquiring a region lock. */
+ final static int LOCK_POSITION = 10;
+
+ /** The extent of the lock file locked when acquiring a region lock. */
+ final static int LOCK_SIZE = 10;
+
+ /**
+ * This is the maximum waiting time in seconds for the test to wait for a response from
+ * the service. This provides ample amount of time for the service to receive the request from
+ * the test, then act, and respond back.
+ */
+ final static int MAX_WAIT_TIME = 7;
+
+ @Override
+ public void tearDown() throws Exception {
+ stopService();
+ super.tearDown();
+ }
+
+ /**
+ * java.nio.channels.FileChannel#tryLock()
+ *
+ * Obtains a remote lock, then attempts to acquire a local lock on the same file,
+ * and checks the behavior.
+ * checkTryLockBehavior(localLockType, remoteLockType, expectedLocalLockResult)
+ * expectedLockLockResult: {@code true} if the returned lock should be valid,
+ * {@code false} otherwise.
+ */
+ public void test_tryLock() throws Exception {
+ checkTryLockBehavior(LockType.TRY_LOCK, LockType.TRY_LOCK, false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.TRY_LOCK, LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.TRY_LOCK, LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.TRY_LOCK, LockType.LOCK, false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.TRY_LOCK, LockType.LOCK_ON_REGION_WITH_LOCK,
+ false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.TRY_LOCK, LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ false /* expectToGetLock */);
+ }
+
+ /**
+ * java.nio.channels.FileChannel#tryLock(long, long, boolean)
+ *
+ * Obtains a remote lock, then attempts to acquire a local lock on the same file,
+ * and checks the behavior.
+ * checkTryLockBehavior(localLockType, remoteLockType, expectedLocalLockResult)
+ * expectedLockLockResult: {@code true} if the returned lock should be valid,
+ * {@code false} otherwise.
+ */
+ public void test_tryLockJJZ_Exclusive() throws Exception {
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK, LockType.TRY_LOCK,
+ false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.LOCK_ON_REGION_WITH_TRY_LOCK, false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK, true /* expectToGetLock */);
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK, false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK,
+ true /* expectToGetLock */);
+
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK, LockType.LOCK,
+ false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.LOCK_ON_REGION_WITH_LOCK, false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK, true /* expectToGetLock */);
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.SHARED_LOCK_ON_REGION_WITH_LOCK, false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK ,
+ true /* expectToGetLock */);
+ }
+
+ /**
+ * java.nio.channels.FileChannel#tryLock(long, long, boolean)
+ *
+ * Obtains a remote lock, then attempts to acquire a local lock on the same file,
+ * and checks the behavior.
+ * checkTryLockBehavior(localLockType, remoteLockType, expectedLocalLockResult)
+ * expectedLockLockResult: {@code true} if the returned lock should be valid,
+ * {@code false} otherwise.
+ */
+ public void test_tryLockJJZ_Shared() throws Exception {
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK, LockType.TRY_LOCK,
+ false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.LOCK_ON_REGION_WITH_TRY_LOCK, false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK, true /* expectToGetLock */);
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK, true /* expectToGetLock */);
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK,
+ true /* expectToGetLock */);
+
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK, LockType.LOCK,
+ false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.LOCK_ON_REGION_WITH_LOCK, false /* expectToGetLock */);
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK, true /* expectToGetLock */);
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.SHARED_LOCK_ON_REGION_WITH_LOCK, true /* expectToGetLock */);
+ checkTryLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ LockType.SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK,
+ true /* expectToGetLock */);
+ }
+
+ /**
+ * java.nio.channels.FileChannel#lock()
+ *
+ * Obtains a remote lock, then attempts to acquire a local lock on the same file,
+ * and checks the behavior.
+ * checkTryLockBehavior(localLockType, remoteLockType, expectedLocalLockResult)
+ * expectedLockLockResult: {@code true} if it blocks the local thread, {@code false} otherwise.
+ */
+ public void test_lock() throws Exception {
+ checkLockBehavior(LockType.LOCK, LockType.LOCK, true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK, LockType.LOCK_ON_REGION_WITH_LOCK,
+ true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK, LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ true /* expectToWait */);
+
+ checkLockBehavior(LockType.LOCK, LockType.TRY_LOCK, true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK, LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK, LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+ true /* expectToWait */);
+ }
+
+ /**
+ * java.nio.channels.FileChannel#lock(long, long, boolean)
+ *
+ * Obtains a remote lock, then attempts to acquire a local lock on the same file,
+ * and checks the behavior.
+ * checkTryLockBehavior(localLockType, remoteLockType, expectedLocalLockResult)
+ * expectedLockLockResult: {@code true} if blocks the local thread, {@code false} otherwise.
+ */
+ public void test_lockJJZ_Exclusive() throws Exception {
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK, LockType.LOCK,
+ true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK, LockType.LOCK_ON_REGION_WITH_LOCK,
+ true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK,
+ LockType.SHARED_LOCK_ON_REGION_WITH_LOCK, true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK,
+ LockType.LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK, false /* expectToWait */);
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK,
+ LockType.SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK, false /* expectToWait */);
+
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK, LockType.TRY_LOCK,
+ true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK, LockType.LOCK_ON_REGION_WITH_TRY_LOCK,
+ true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK,
+ LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK, true /* expectToWait */);
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK,
+ LockType.LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK, false /* expectToWait */);
+ checkLockBehavior(LockType.LOCK_ON_REGION_WITH_LOCK,
+ LockType.SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK,
+ false /* expectToWait */);
+ }
+
+ /**
+ * java.nio.channels.FileChannel#lock(long, long, boolean)
+ *
+ * Obtains a remote lock, then attempts to acquire a local lock on the same file,
+ * and checks the behavior.
+ * checkTryLockBehavior(localLockType, remoteLockType, expectedLocalLockResult)
+ * expectedLockLockResult: {@code true} if blocks the local thread, {@code false} otherwise.
+ */
+ public void test_lockJJZ_Shared() throws Exception {
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK, LockType.LOCK,
+ true /* expectToWait */);
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ LockType.LOCK_ON_REGION_WITH_LOCK, true /* expectToWait */);
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ LockType.SHARED_LOCK_ON_REGION_WITH_LOCK, false /* expectToWait */);
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ LockType.LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK, false /* expectToWait */);
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ LockType.SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK, false /* expectToWait */);
+
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK, LockType.TRY_LOCK,
+ true /* expectToWait */);
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ LockType.LOCK_ON_REGION_WITH_TRY_LOCK, true /* expectToWait */);
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ LockType.SHARED_LOCK_ON_REGION_WITH_TRY_LOCK, false /* expectToWait */);
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ LockType.LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK, false /* expectToWait */);
+ checkLockBehavior(LockType.SHARED_LOCK_ON_REGION_WITH_LOCK,
+ LockType.SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK,
+ false /* expectToWait */);
+ }
+
+ /**
+ * Checks the behavior of java.nio.Channels.FileChannel#tryLock() and #tryLock(J, J, Z)
+ *
+ * @param localLockType the type of lock to be acquired by the test
+ * @param remoteLockType the type of lock to be acquired by the remote service
+ * @param expectToGetLock {@code true}, if the lock should be acquired even when the
+ * service holds a {@code remoteLockType} lock, false otherwise.
+ */
+ private void checkTryLockBehavior(LockType localLockType, LockType remoteLockType,
+ boolean expectToGetLock) throws Exception {
+ IntentReceiver.resetReceiverState();
+
+ // Request that the remote lock be obtained.
+ getContext().startService(new Intent(getContext(), LockHoldingService.class)
+ .putExtra(LockHoldingService.LOCK_TYPE_KEY, remoteLockType));
+
+ // Wait for a signal that the remote lock is definitely held.
+ assertTrue(IntentReceiver.lockHeldLatch.await(MAX_WAIT_TIME, SECONDS));
+
+ // Try to acquire the local lock in all cases and check whether it could be acquired or
+ // not as expected.
+ if (expectToGetLock) {
+ FileLock fileLock = acquire(localLockType);
+ assertNotNull(fileLock);
+ assertTrue(fileLock.isValid());
+ } else {
+ assertNull(acquire(localLockType));
+ }
+ // Release the remote lock.
+ stopService();
+ }
+
+ /**
+ * Checks the java.nio.channels.FileChannel.lock()/lock(J, J, Z) behavior.
+ *
+ * @param localLockType type of lock to be acquired by the test
+ * @param remoteLockType type of lock to be acquired by the remote service.
+ * @param expectToWait {@code true}, if the local thread must wait for the remote
+ * service to release the lock, {@code false} otherwise.
+ */
+ private void checkLockBehavior(LockType localLockType, LockType remoteLockType,
+ boolean expectToWait) throws Exception {
+ IntentReceiver.resetReceiverState();
+
+ // The amount of time the remote service should hold lock.
+ long remoteLockHoldTimeMillis = 5000;
+
+ // The amount of time test should get to try to acquire the lock.
+ long sufficientOverlappingTimeInMillis = 2000;
+
+ // This is the allowable delta in the time between the time recorded after the service
+ // released the lock and the time recorded after the test obtained the lock.
+ long lockReleasedAndReacquiredTimeDeltaInMillis = 500;
+
+ // Tell the service to acquire a remote lock.
+ Intent sendIntent = new Intent(getContext(), LockHoldingService.class)
+ .putExtra(LockHoldingService.TIME_TO_HOLD_LOCK_KEY, remoteLockHoldTimeMillis)
+ .putExtra(LockHoldingService.LOCK_TYPE_KEY, remoteLockType)
+ .putExtra(LockHoldingService.LOCK_BEHAVIOR_RELEASE_AND_NOTIFY_KEY, true);
+
+ getContext().startService(sendIntent);
+
+ // Wait for the service to hold the lock and notify for the same.
+ assertTrue(IntentReceiver.lockHeldLatch.await(MAX_WAIT_TIME, SECONDS));
+
+ long localLockNotObtainedTime = System.currentTimeMillis();
+
+ // Acquire the lock locally.
+ FileLock fileLock = acquire(localLockType);
+ long localLockObtainedTime = System.currentTimeMillis();
+
+ // Wait until the remote lock has definitely been released.
+ assertTrue(IntentReceiver.lockReleasedLatch.await(MAX_WAIT_TIME, SECONDS));
+
+ Bundle remoteLockReleasedBundle = IntentReceiver.lockReleasedBundle;
+ long remoteLockNotReleasedTime =
+ remoteLockReleasedBundle.getLong(LockHoldingService.LOCK_NOT_YET_RELEASED_TIMESTAMP);
+ long remoteLockReleasedTime =
+ remoteLockReleasedBundle.getLong(LockHoldingService.LOCK_DEFINITELY_RELEASED_TIMESTAMP);
+
+ // We want the test to be notified well before the service releases the lock, so that
+ // we can be sure that it tried obtaining the lock before the service actually released it.
+ // Therefore, a two seconds time interval provides the test to get prepare and try to obtain
+ // the lock. If this fails, it doesn't mean they definitely didn't overlap
+ // but we can't be sure and the test may not be valid. This is why we hold the lock
+ // remotely for a long time compared to the delays we expect for intents to propagate
+ // between processes.
+ assertTrue(remoteLockNotReleasedTime - localLockNotObtainedTime >
+ sufficientOverlappingTimeInMillis);
+
+ if (expectToWait) {
+
+ // The remoteLockReleaseTime is captured after the lock was released by the
+ // service. The localLockObtainedTime is captured after the lock was obtained by this
+ // thread. Therefore, there is a degree of slop inherent in the two times. We assert
+ // that they are "close" to each other, but we cannot assert any ordering.
+ assertTrue(Math.abs(localLockObtainedTime - remoteLockReleasedTime) <
+ lockReleasedAndReacquiredTimeDeltaInMillis);
+ } else {
+ // The remoteLockNotReleaseTime is captured before the lock was released by the
+ // service. The localLockObtainedTime is captured after the lock was obtained by this
+ // thread. The local thread should be able to get the lock before the remote thread
+ // definitely release it. If this test fails it may not indicate a problem, but it
+ // indicates we cannot be sure the test was successful the local lock attempt and the
+ // remote lock attempt did not overlap.
+ assertTrue(localLockObtainedTime < remoteLockNotReleasedTime);
+ }
+
+ // Asserting if the fileLock is valid.
+ assertTrue(fileLock.isValid());
+ stopService();
+ }
+
+ /**
+ * Requests and waits for the service to stop
+ */
+ void stopService() throws Exception {
+ getContext().stopService(new Intent(getContext(), LockHoldingService.class));
+ assertTrue(IntentReceiver.onStopLatch.await(MAX_WAIT_TIME, SECONDS));
+ deleteDir();
+ }
+
+ enum LockType {
+
+ /** Equivalent to {@code tryLock()} */
+ TRY_LOCK,
+
+ /** Equivalent to {@code tryLock({@link #LOCK_POSITION}, {@link #LOCK_SIZE}, false)} */
+ LOCK_ON_REGION_WITH_TRY_LOCK,
+
+ /**
+ * Equivalent to {@code tryLock({@code {@link #LOCK_POSITION} + {@link #LOCK_SIZE}},
+ * {@link #LOCK_SIZE}, false)}
+ */
+ LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK,
+
+ /** Equivalent to {@code tryLock({@link #LOCK_POSITION}, {@link #LOCK_SIZE}, true)} */
+ SHARED_LOCK_ON_REGION_WITH_TRY_LOCK,
+
+ /**
+ * Equivalent to {@code tryLock({@code {@link #LOCK_POSITION} + {@link #LOCK_SIZE}},
+ * {@link #LOCK_SIZE}, true)}
+ */
+ SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK,
+
+ /** Equivalent to {@code lock()} */
+ LOCK,
+
+ /** Equivalent to {code lock({@link #LOCK_POSITION}, {@link #LOCK_SIZE}, false)} */
+ LOCK_ON_REGION_WITH_LOCK,
+
+ /**
+ * Equivalent to {@code lock({@code {@link #LOCK_POSITION} + {@link #LOCK_SIZE}},
+ * {@link #LOCK_SIZE}, false)}
+ */
+ LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK,
+
+ /** Equivalent to {@code lock({@link #LOCK_POSITION}, {@link #LOCK_SIZE}, true)} */
+ SHARED_LOCK_ON_REGION_WITH_LOCK,
+
+ /**
+ * Equivalent to {@code lock({@code {@link #LOCK_POSITION} + {@link #LOCK_SIZE}},
+ * {@link #LOCK_SIZE}, true)}
+ */
+ SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK,
+ }
+
+ /**
+ * Tries to acquire a lock of {@code lockType} on the file returned by
+ * {@link #createFileInDir()} method.
+ *
+ * @param lockType a {@link LockType} enum.
+ * Permitted lock types:
+ * {@link LockType#TRY_LOCK}
+ * {@link LockType#LOCK_ON_REGION_WITH_TRY_LOCK}
+ * {@link LockType#LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK}
+ * {@link LockType#SHARED_LOCK_ON_REGION_WITH_TRY_LOCK}
+ * {@link LockType#SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK}
+ * {@link LockType#LOCK}
+ * {@link LockType#LOCK_ON_REGION_WITH_LOCK}
+ * {@link LockType#LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK}
+ * {@link LockType#SHARED_LOCK_ON_REGION_WITH_LOCK}
+ * {@link LockType#SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK}
+ * @return Returns the lock returned by the lock method.
+ * @throws UnsupportedOperationException
+ * If the {@code lockType} is of non recognized type.
+ */
+ static FileLock acquire(LockType lockType) throws IOException {
+ File file = createFileInDir();
+ file.createNewFile();
+ switch (lockType) {
+ case TRY_LOCK:
+ return new FileOutputStream(file).getChannel().tryLock();
+ case LOCK_ON_REGION_WITH_TRY_LOCK:
+ return new FileOutputStream(file).getChannel()
+ .tryLock(LOCK_POSITION, LOCK_SIZE, false /*isShared*/);
+ case LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK:
+ return new FileOutputStream(file).getChannel()
+ .tryLock(LOCK_POSITION + LOCK_SIZE, LOCK_SIZE, false /*isShared*/);
+ case SHARED_LOCK_ON_REGION_WITH_TRY_LOCK:
+ return new FileInputStream(file).getChannel()
+ .tryLock(LOCK_POSITION, LOCK_SIZE, true /*isShared*/);
+ case SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_TRY_LOCK:
+ return new FileInputStream(file).getChannel()
+ .tryLock(LOCK_POSITION + LOCK_SIZE, LOCK_SIZE, true /*isShared*/);
+ case LOCK:
+ return new FileOutputStream(file).getChannel().lock();
+ case LOCK_ON_REGION_WITH_LOCK:
+ return new FileOutputStream(file).getChannel()
+ .lock(LOCK_POSITION, LOCK_SIZE, false /*isShared*/);
+ case LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK:
+ return new FileOutputStream(file).getChannel()
+ .lock(LOCK_POSITION + LOCK_SIZE, LOCK_SIZE, false /*isShared*/);
+ case SHARED_LOCK_ON_REGION_WITH_LOCK:
+ return new FileInputStream(file).getChannel()
+ .lock(LOCK_POSITION, LOCK_SIZE, true /*isShared*/);
+ case SHARED_LOCK_ON_NON_OVERLAPPING_REGION_WITH_LOCK:
+ return new FileInputStream(file).getChannel()
+ .lock(LOCK_POSITION + LOCK_SIZE, LOCK_SIZE, true /*isShared*/);
+ default:
+ throw new UnsupportedOperationException("Unknown lock type");
+ }
+ }
+
+ /**
+ * Creates a file named {@link #FILE_NAME} inside a directory named {@link #DIR_NAME} on
+ * the external storage directory.
+ */
+ static File createFileInDir() throws IOException {
+ File dir = new File(Environment.getExternalStorageDirectory(), DIR_NAME);
+ if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ throw new IOException("External storage is not mounted");
+ } else if (!dir.mkdirs() && !dir.isDirectory()) {
+ throw new IOException("Cannot create directory for device info files");
+ } else {
+ return new File(dir, FILE_NAME);
+ }
+ }
+
+ /**
+ * Deletes the folder {@link #DIR_NAME} on the external storage directory along with all the
+ * files inside it.
+ */
+ static void deleteDir() {
+ File dir = new File(Environment.getExternalStorageDirectory(), DIR_NAME);
+ if (dir.isDirectory()) {
+ String[] children = dir.list();
+ for (String child : children) {
+ new File(dir, child).delete();
+ }
+ dir.delete();
+ }
+ }
+
+ /**
+ * Listens to broadcasts sent by the LockHoldingService and records information / provides
+ * latches so the test code can synchronize until it is informed the service has acted on
+ * requests it has sent.
+ */
+ public static class IntentReceiver extends BroadcastReceiver {
+
+ static CountDownLatch onStartLatch;
+
+ static CountDownLatch onStopLatch;
+
+ static CountDownLatch lockHeldLatch;
+
+ static volatile Bundle lockHeldBundle;
+
+ static CountDownLatch lockReleasedLatch;
+
+ static volatile Bundle lockReleasedBundle;
+
+ /**
+ * Reset the IntentReceiver for a new test. Assumes no intents will be received from prior
+ * tests.
+ */
+ public static synchronized void resetReceiverState() {
+ onStartLatch = new CountDownLatch(1);
+ onStopLatch = new CountDownLatch(1);
+ lockHeldLatch = new CountDownLatch(1);
+ lockReleasedLatch = new CountDownLatch(1);
+ lockHeldBundle = null;
+ lockReleasedBundle = null;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String msg = intent.getStringExtra(LockHoldingService.NOTIFICATION_KEY);
+ switch (msg) {
+ case LockHoldingService.NOTIFICATION_START:
+ onStartLatch.countDown();
+ break;
+ case LockHoldingService.NOTIFICATION_STOP:
+ onStopLatch.countDown();
+ break;
+ case LockHoldingService.NOTIFICATION_LOCK_HELD:
+ lockHeldBundle = intent.getExtras();
+ lockHeldLatch.countDown();
+ break;
+ case LockHoldingService.NOTIFICATION_LOCK_RELEASED:
+ lockReleasedBundle = intent.getExtras();
+ lockReleasedLatch.countDown();
+ break;
+ }
+ }
+ }
+}
+
diff --git a/tests/tests/libcorefileio/src/android/cts/FileChannelTryLockTest.java b/tests/tests/libcorefileio/src/android/cts/FileChannelTryLockTest.java
deleted file mode 100644
index 61a59ca6f46..00000000000
--- a/tests/tests/libcorefileio/src/android/cts/FileChannelTryLockTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.cts;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Environment;
-import android.test.AndroidTestCase;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.channels.FileLock;
-import java.nio.channels.OverlappingFileLockException;
-
-@SuppressWarnings("deprecation")
-public class FileChannelTryLockTest extends AndroidTestCase {
-
- final static String dirName = "CtsFIleIOTest";
-
- final static String sharedFileName = "sharedFile";
-
- public void testFileLockWithMultipleProcess() throws InterruptedException, IOException {
- IntentReceiver receiver = new IntentReceiver();
- getContext().startService(new Intent(getContext(), LockHoldingService.class));
- synchronized (receiver.notifier) {
- receiver.notifier.wait(10000);
- }
- File sharedFile = createFileInDir(dirName, sharedFileName);
- assertNull(new FileOutputStream(sharedFile).getChannel().tryLock());
- getContext().stopService(new Intent(getContext(), LockHoldingService.class));
- }
-
- public void testFileLockWithSingleProcess() throws IOException {
- File file = createFileInDir(dirName, "sharedFileForSingleProcess");
- FileLock fileLock1 = new FileOutputStream(file).getChannel().tryLock();
- try {
- new FileOutputStream(file).getChannel().tryLock();
- fail();
- } catch (OverlappingFileLockException expected) {
- }
- }
-
- static File createFileInDir(String dirName, String fileName) throws IOException {
- File dir = new File(Environment.getExternalStorageDirectory(), dirName);
- if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- throw new IOException("External storage is not mounted");
- } else if (!dir.mkdirs() && !dir.isDirectory()) {
- throw new IOException("Cannot create directory for device info files");
- } else {
- return new File(dir, fileName);
- }
- }
-
- static void deleteDir() {
- File dir = new File(Environment.getExternalStorageDirectory(), dirName);
- if (dir.isDirectory()) {
- String[] children = dir.list();
- for (int i = 0; i < children.length; i++) {
- new File(dir, children[i]).delete();
- }
- dir.delete();
- }
- }
-
- @Override
- public void tearDown() throws Exception {
- getContext().stopService(new Intent(getContext(), LockHoldingService.class));
- deleteDir();
- }
-
- public static class IntentReceiver extends BroadcastReceiver {
-
- public final static Object notifier = new Object();
-
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (notifier) {
- notifier.notify();
- }
- }
- }
-}
-
diff --git a/tests/tests/libcorefileio/src/android/cts/LockHoldingService.java b/tests/tests/libcorefileio/src/android/cts/LockHoldingService.java
index be6a3526125..6ac73b0df05 100644
--- a/tests/tests/libcorefileio/src/android/cts/LockHoldingService.java
+++ b/tests/tests/libcorefileio/src/android/cts/LockHoldingService.java
@@ -21,18 +21,74 @@ import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
-import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileLock;
+/**
+ * A Service that listens for commands from the FileChannelInterProcessLockTest to acquire locks of
+ * different types. It exists to test the behavior when file locks are acquired/released across
+ * multiple processes.
+ */
public class LockHoldingService extends Service {
- final String TAG = "CtsLibcoreFileIOTestCases";
+ /**
+ * The key of the Bundle extra used to record a time after a lock is released by the service.
+ */
+ static final String LOCK_DEFINITELY_RELEASED_TIMESTAMP = "lockReleasedTimestamp";
+
+ /**
+ * The key of the Bundle extra used to record just before the lock is released by the service.
+ */
+ static final String LOCK_NOT_YET_RELEASED_TIMESTAMP = "lockNotReleasedTimestamp";
+
+ /**
+ * The key of the Bundle extra used to send general notifications to the test.
+ */
+ static final String NOTIFICATION_KEY = "notification";
+
+ /**
+ * The value for the notification sent to the test after the service starts.
+ */
+ static final String NOTIFICATION_START = "onStart";
+
+ /**
+ * The value for the notification sent to the test just before the service stops.
+ */
+ static final String NOTIFICATION_STOP = "onStop";
+
+ /**
+ * The value for the notification sent to the test after the lock is acquired.
+ */
+ static final String NOTIFICATION_LOCK_HELD = "lockHeld";
+
+ /**
+ * The value for the notification sent to the test after the lock is released
+ */
+ static final String NOTIFICATION_LOCK_RELEASED = "lockReleased";
- File file = null;
+ /**
+ * The key of the Bundle extra used to send time for which the service should wait before
+ * releasing the lock.
+ */
+ static final String TIME_TO_HOLD_LOCK_KEY = "timeToHoldLock";
- FileLock fileLock = null;
+ /**
+ * The key of the Bundle extra used for the type of lock to be held.
+ */
+ static final String LOCK_TYPE_KEY = "lockType";
+
+ /**
+ * The key of the Bundle extra used to let he service know whether to release the lock after
+ * some time.
+ */
+ static final String LOCK_BEHAVIOR_RELEASE_AND_NOTIFY_KEY = "releaseAndNotify";
+
+ static final String ACTION_TYPE_FOR_INTENT_COMMUNICATION
+ = "android.cts.CtsLibcoreFileIOTestCases";
+
+ final String LOG_MESSAGE_TAG = "CtsLibcoreFileIOTestCases";
+
+ private FileLock fileLock = null;
public IBinder onBind(Intent intent) {
return null;
@@ -41,27 +97,81 @@ public class LockHoldingService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startID) {
try {
- this.file = FileChannelTryLockTest.createFileInDir(FileChannelTryLockTest.dirName,
- FileChannelTryLockTest.sharedFileName);
- try {
- this.fileLock = new FileOutputStream(file).getChannel().tryLock();
- } catch (IOException e) {
- Log.e(TAG, e.getMessage());
+ if (intent.getBooleanExtra(LOCK_BEHAVIOR_RELEASE_AND_NOTIFY_KEY, false)) {
+ acquireLockAndThenWaitThenRelease(intent);
+ } else {
+ acquireLock(intent);
}
- } catch (IOException e) {
- Log.e(TAG, e.getMessage());
+ } catch (Exception e) {
+ Log.e(LOG_MESSAGE_TAG, e.getMessage());
}
- sendBroadcast(new Intent().setAction("android.cts.CtsLibcoreFileIOTestCases"));
return START_STICKY;
}
+ /**
+ * Acquires the lock asked by the test indefinitely.
+ */
+ private void acquireLock(Intent intent) throws IOException {
+ FileChannelInterProcessLockTest.LockType lockType =
+ (FileChannelInterProcessLockTest.LockType)intent.getSerializableExtra(
+ LOCK_TYPE_KEY);
+
+ // Acquire the lock based on the information contained in the intent received.
+ this.fileLock = FileChannelInterProcessLockTest.acquire(lockType);
+ Intent responseIntent = new Intent().putExtra(NOTIFICATION_KEY, NOTIFICATION_LOCK_HELD)
+ .setAction(ACTION_TYPE_FOR_INTENT_COMMUNICATION);
+ sendBroadcast(responseIntent);
+ }
+
+ /**
+ * Acquires and holds the lock for a time specified by the test. Sends a broadcast message after
+ * releasing the lock.
+ */
+ private void acquireLockAndThenWaitThenRelease(Intent intent)
+ throws IOException, InterruptedException {
+ long lockHoldTimeMillis = intent.getLongExtra(TIME_TO_HOLD_LOCK_KEY, 0);
+
+ // Acquire the lock.
+ FileChannelInterProcessLockTest.LockType lockType =
+ (FileChannelInterProcessLockTest.LockType)intent.getSerializableExtra(
+ LOCK_TYPE_KEY);
+ this.fileLock = FileChannelInterProcessLockTest.acquire(lockType);
+
+ // Signal the lock is now held.
+ Intent heldIntent = new Intent()
+ .putExtra(NOTIFICATION_KEY, NOTIFICATION_LOCK_HELD)
+ .setAction(ACTION_TYPE_FOR_INTENT_COMMUNICATION);
+ sendBroadcast(heldIntent);
+
+ Thread.sleep(lockHoldTimeMillis);
+
+ long lockNotReleasedTimestamp = System.currentTimeMillis();
+
+ // Release the lock
+ fileLock.release();
+
+ long lockReleasedTimestamp = System.currentTimeMillis();
+
+ // Signal the lock is released and some information about timing.
+ Intent releaseIntent = new Intent()
+ .putExtra(NOTIFICATION_KEY, NOTIFICATION_LOCK_RELEASED)
+ .putExtra(LOCK_NOT_YET_RELEASED_TIMESTAMP, lockNotReleasedTimestamp)
+ .putExtra(LOCK_DEFINITELY_RELEASED_TIMESTAMP, lockReleasedTimestamp)
+ .setAction(ACTION_TYPE_FOR_INTENT_COMMUNICATION);
+ sendBroadcast(releaseIntent);
+ }
+
@Override
public void onDestroy() {
try {
- fileLock.close();
+ if (fileLock != null) {
+ fileLock.release();
+ }
} catch (IOException e) {
- Log.e(TAG, e.getMessage());
+ Log.e(LOG_MESSAGE_TAG, e.getMessage());
}
- FileChannelTryLockTest.deleteDir();
+ Intent intent = new Intent().putExtra(NOTIFICATION_KEY, NOTIFICATION_STOP)
+ .setAction(ACTION_TYPE_FOR_INTENT_COMMUNICATION);
+ sendBroadcast(intent);
}
}