174 lines
5.6 KiB
Java
174 lines
5.6 KiB
Java
/*
|
|
* Copyright (C) 2012 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.os;
|
|
|
|
import android.compat.annotation.UnsupportedAppUsage;
|
|
import android.content.Context;
|
|
import android.util.Log;
|
|
|
|
/**
|
|
* Advisory wakelock-like mechanism by which processes that should not be interrupted for
|
|
* OTA/update purposes can so advise the OS. This is particularly relevant for headless
|
|
* or kiosk-like operation.
|
|
*
|
|
* @hide
|
|
*/
|
|
public class UpdateLock {
|
|
private static final boolean DEBUG = false;
|
|
private static final String TAG = "UpdateLock";
|
|
|
|
private static IUpdateLock sService;
|
|
private static void checkService() {
|
|
if (sService == null) {
|
|
sService = IUpdateLock.Stub.asInterface(
|
|
ServiceManager.getService(Context.UPDATE_LOCK_SERVICE));
|
|
}
|
|
}
|
|
|
|
IBinder mToken;
|
|
int mCount = 0;
|
|
boolean mRefCounted = true;
|
|
boolean mHeld = false;
|
|
final String mTag;
|
|
|
|
/**
|
|
* Broadcast Intent action sent when the global update lock state changes,
|
|
* i.e. when the first locker acquires an update lock, or when the last
|
|
* locker releases theirs. The broadcast is sticky but is sent only to
|
|
* registered receivers.
|
|
*/
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
|
public static final String UPDATE_LOCK_CHANGED = "android.os.UpdateLock.UPDATE_LOCK_CHANGED";
|
|
|
|
/**
|
|
* Boolean Intent extra on the UPDATE_LOCK_CHANGED sticky broadcast, indicating
|
|
* whether now is an appropriate time to interrupt device activity with an
|
|
* update operation. True means that updates are okay right now; false indicates
|
|
* that perhaps later would be a better time.
|
|
*/
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
|
public static final String NOW_IS_CONVENIENT = "nowisconvenient";
|
|
|
|
/**
|
|
* Long Intent extra on the UPDATE_LOCK_CHANGED sticky broadcast, marking the
|
|
* wall-clock time [in UTC] at which the broadcast was sent. Note that this is
|
|
* in the System.currentTimeMillis() time base, which may be non-monotonic especially
|
|
* around reboots.
|
|
*/
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
|
public static final String TIMESTAMP = "timestamp";
|
|
|
|
/**
|
|
* Construct an UpdateLock instance.
|
|
* @param tag An arbitrary string used to identify this lock instance in dump output.
|
|
*/
|
|
public UpdateLock(String tag) {
|
|
mTag = tag;
|
|
mToken = new Binder();
|
|
}
|
|
|
|
/**
|
|
* Change the refcount behavior of this update lock.
|
|
*/
|
|
public void setReferenceCounted(boolean isRefCounted) {
|
|
if (DEBUG) {
|
|
Log.v(TAG, "setting refcounted=" + isRefCounted + " : " + this);
|
|
}
|
|
mRefCounted = isRefCounted;
|
|
}
|
|
|
|
/**
|
|
* Is this lock currently held?
|
|
*/
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
|
public boolean isHeld() {
|
|
synchronized (mToken) {
|
|
return mHeld;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Acquire an update lock.
|
|
*/
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
|
public void acquire() {
|
|
if (DEBUG) {
|
|
Log.v(TAG, "acquire() : " + this, new RuntimeException("here"));
|
|
}
|
|
checkService();
|
|
synchronized (mToken) {
|
|
acquireLocked();
|
|
}
|
|
}
|
|
|
|
private void acquireLocked() {
|
|
if (!mRefCounted || mCount++ == 0) {
|
|
if (sService != null) {
|
|
try {
|
|
sService.acquireUpdateLock(mToken, mTag);
|
|
} catch (RemoteException e) {
|
|
Log.e(TAG, "Unable to contact service to acquire");
|
|
}
|
|
}
|
|
mHeld = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Release this update lock.
|
|
*/
|
|
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
|
|
public void release() {
|
|
if (DEBUG) Log.v(TAG, "release() : " + this, new RuntimeException("here"));
|
|
checkService();
|
|
synchronized (mToken) {
|
|
releaseLocked();
|
|
}
|
|
}
|
|
|
|
private void releaseLocked() {
|
|
if (!mRefCounted || --mCount == 0) {
|
|
if (sService != null) {
|
|
try {
|
|
sService.releaseUpdateLock(mToken);
|
|
} catch (RemoteException e) {
|
|
Log.e(TAG, "Unable to contact service to release");
|
|
}
|
|
}
|
|
mHeld = false;
|
|
}
|
|
if (mCount < 0) {
|
|
throw new RuntimeException("UpdateLock under-locked");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void finalize() throws Throwable {
|
|
synchronized (mToken) {
|
|
// if mHeld is true, sService must be non-null
|
|
if (mHeld) {
|
|
Log.wtf(TAG, "UpdateLock finalized while still held");
|
|
try {
|
|
sService.releaseUpdateLock(mToken);
|
|
} catch (RemoteException e) {
|
|
Log.e(TAG, "Unable to contact service to release");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|