18662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate/* 28662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Copyright (C) 2012 The Android Open Source Project 38662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * 48662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Licensed under the Apache License, Version 2.0 (the "License"); 58662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * you may not use this file except in compliance with the License. 68662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * You may obtain a copy of the License at 78662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * 88662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * http://www.apache.org/licenses/LICENSE-2.0 98662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * 108662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Unless required by applicable law or agreed to in writing, software 118662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * distributed under the License is distributed on an "AS IS" BASIS, 128662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * See the License for the specific language governing permissions and 148662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * limitations under the License. 158662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 168662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 178662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tatepackage android.os; 188662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 198662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.content.Context; 208662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.util.Log; 218662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 228662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate/** 238662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Advisory wakelock-like mechanism by which processes that should not be interrupted for 248662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * OTA/update purposes can so advise the OS. This is particularly relevant for headless 258662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * or kiosk-like operation. 268662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * 278662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * @hide 288662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 298662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tatepublic class UpdateLock { 308662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate private static final boolean DEBUG = false; 318662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate private static final String TAG = "UpdateLock"; 328662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 338662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate private static IUpdateLock sService; 348662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate private static void checkService() { 358662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (sService == null) { 368662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate sService = IUpdateLock.Stub.asInterface( 378662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate ServiceManager.getService(Context.UPDATE_LOCK_SERVICE)); 388662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 398662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 408662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 418662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate IBinder mToken; 428662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate int mCount = 0; 438662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate boolean mRefCounted = true; 448662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate boolean mHeld = false; 458662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate final String mTag; 468662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 478662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate /** 488662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Broadcast Intent action sent when the global update lock state changes, 498662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * i.e. when the first locker acquires an update lock, or when the last 508662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * locker releases theirs. The broadcast is sticky but is sent only to 518662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * registered receivers. 528662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 538662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate public static final String UPDATE_LOCK_CHANGED = "android.os.UpdateLock.UPDATE_LOCK_CHANGED"; 548662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 558662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate /** 568662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Boolean Intent extra on the UPDATE_LOCK_CHANGED sticky broadcast, indicating 578662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * whether now is an appropriate time to interrupt device activity with an 588662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * update operation. True means that updates are okay right now; false indicates 598662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * that perhaps later would be a better time. 608662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 618662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate public static final String NOW_IS_CONVENIENT = "nowisconvenient"; 628662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 638662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate /** 648662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Long Intent extra on the UPDATE_LOCK_CHANGED sticky broadcast, marking the 658662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * wall-clock time [in UTC] at which the broadcast was sent. Note that this is 668662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * in the System.currentTimeMillis() time base, which may be non-monotonic especially 678662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * around reboots. 688662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 698662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate public static final String TIMESTAMP = "timestamp"; 708662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 718662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate /** 728662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Construct an UpdateLock instance. 738662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * @param tag An arbitrary string used to identify this lock instance in dump output. 748662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 758662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate public UpdateLock(String tag) { 768662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate mTag = tag; 778662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate mToken = new Binder(); 788662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 798662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 808662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate /** 818662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Change the refcount behavior of this update lock. 828662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 838662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate public void setReferenceCounted(boolean isRefCounted) { 848662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (DEBUG) { 858662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate Log.v(TAG, "setting refcounted=" + isRefCounted + " : " + this); 868662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 878662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate mRefCounted = isRefCounted; 888662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 898662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 908662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate /** 918662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Is this lock currently held? 928662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 938662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate public boolean isHeld() { 948662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate synchronized (mToken) { 958662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate return mHeld; 968662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 978662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 988662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 998662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate /** 1008662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Acquire an update lock. 1018662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 1028662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate public void acquire() { 1038662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (DEBUG) { 1048662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate Log.v(TAG, "acquire() : " + this, new RuntimeException("here")); 1058662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1068662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate checkService(); 1078662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate synchronized (mToken) { 1088662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate acquireLocked(); 1098662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1108662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1118662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 1128662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate private void acquireLocked() { 1138662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (!mRefCounted || mCount++ == 0) { 1148662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (sService != null) { 1158662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate try { 1168662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate sService.acquireUpdateLock(mToken, mTag); 1178662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } catch (RemoteException e) { 1188662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate Log.e(TAG, "Unable to contact service to acquire"); 1198662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1208662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1218662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate mHeld = true; 1228662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1238662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1248662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 1258662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate /** 1268662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate * Release this update lock. 1278662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate */ 1288662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate public void release() { 1298662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (DEBUG) Log.v(TAG, "release() : " + this, new RuntimeException("here")); 1308662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate checkService(); 1318662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate synchronized (mToken) { 1328662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate releaseLocked(); 1338662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1348662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1358662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 1368662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate private void releaseLocked() { 1378662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (!mRefCounted || --mCount == 0) { 1388662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (sService != null) { 1398662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate try { 1408662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate sService.releaseUpdateLock(mToken); 1418662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } catch (RemoteException e) { 1428662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate Log.e(TAG, "Unable to contact service to release"); 1438662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1448662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1458662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate mHeld = false; 1468662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1478662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (mCount < 0) { 1488662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate throw new RuntimeException("UpdateLock under-locked"); 1498662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1508662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1518662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate 1528662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate @Override 1538662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate protected void finalize() throws Throwable { 1548662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate synchronized (mToken) { 1558662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate // if mHeld is true, sService must be non-null 1568662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate if (mHeld) { 1578662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate Log.wtf(TAG, "UpdateLock finalized while still held"); 1588662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate try { 1598662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate sService.releaseUpdateLock(mToken); 1608662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } catch (RemoteException e) { 1618662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate Log.e(TAG, "Unable to contact service to release"); 1628662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1638662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1648662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1658662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate } 1668662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate} 167