| /* |
| * 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; |
| } |
| } |
| } |
| } |
| |