blob: 0df884683ff7eb9c407e807286f7ac9848502981 [file] [log] [blame]
/*
* 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.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import java.io.IOException;
import java.nio.channels.FileLock;
import java.util.concurrent.ExecutionException;
import static android.cts.FileChannelInterProcessLockTest.ChannelType;
import static android.cts.FileChannelInterProcessLockTest.LockType;
/**
* 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 {
/**
* 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";
/**
* 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";
/**
* 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 for the type of the channel that acquires the lock.
*/
static final String CHANNEL_TYPE_KEY = "channelType";
/**
* 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;
}
@Override
public int onStartCommand(Intent intent, int flags, int startID) {
try {
if (intent.getBooleanExtra(LOCK_BEHAVIOR_RELEASE_AND_NOTIFY_KEY, false)) {
acquireLockAndThenWaitThenRelease(intent);
} else {
acquireLock(intent);
}
} catch (Exception e) {
Log.e(LOG_MESSAGE_TAG, "Exception acquire lock", e);
}
return START_STICKY;
}
/**
* Acquires the lock asked by the test indefinitely.
*/
private void acquireLock(Intent intent) throws IOException,
InterruptedException, ExecutionException {
LockType lockType = (LockType) intent.getSerializableExtra(LOCK_TYPE_KEY);
ChannelType channelType = (ChannelType) intent.getSerializableExtra(CHANNEL_TYPE_KEY);
// Acquire the lock based on the information contained in the intent received.
this.fileLock = FileChannelInterProcessLockTest.acquire(this, lockType, channelType);
Intent responseIntent = new Intent()
.setPackage("android.libcorefileio.cts")
.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, ExecutionException {
long lockHoldTimeMillis = intent.getLongExtra(TIME_TO_HOLD_LOCK_KEY, 0);
// Acquire the lock.
LockType lockType = (LockType) intent.getSerializableExtra(LOCK_TYPE_KEY);
ChannelType channelType = (ChannelType) intent.getSerializableExtra(CHANNEL_TYPE_KEY);
this.fileLock = FileChannelInterProcessLockTest.acquire(this, lockType, channelType);
// Signal the lock is now held.
Intent heldIntent = new Intent()
.setPackage("android.libcorefileio.cts")
.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()
.setPackage("android.libcorefileio.cts")
.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 {
if (fileLock != null) {
fileLock.release();
}
} catch (IOException e) {
Log.e(LOG_MESSAGE_TAG, e.getMessage());
}
Intent intent = new Intent()
.setPackage("android.libcorefileio.cts")
.putExtra(NOTIFICATION_KEY, NOTIFICATION_STOP)
.setAction(ACTION_TYPE_FOR_INTENT_COMMUNICATION);
sendBroadcast(intent);
}
}