1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.pm.PackageManager; 22 import android.os.Binder; 23 import android.os.Handler; 24 import android.os.IBinder; 25 import android.os.IUpdateLock; 26 import android.os.RemoteException; 27 import android.os.TokenWatcher; 28 import android.os.UpdateLock; 29 import android.os.UserHandle; 30 import android.util.Slog; 31 32 import com.android.internal.util.DumpUtils; 33 34 import java.io.FileDescriptor; 35 import java.io.PrintWriter; 36 37 public class UpdateLockService extends IUpdateLock.Stub { 38 static final boolean DEBUG = false; 39 static final String TAG = "UpdateLockService"; 40 41 // signatureOrSystem required to use update locks 42 static final String PERMISSION = "android.permission.UPDATE_LOCK"; 43 44 Context mContext; 45 LockWatcher mLocks; 46 47 class LockWatcher extends TokenWatcher { LockWatcher(Handler h, String tag)48 LockWatcher(Handler h, String tag) { 49 super(h, tag); 50 } 51 acquired()52 public void acquired() { 53 if (DEBUG) { 54 Slog.d(TAG, "first acquire; broadcasting convenient=false"); 55 } 56 sendLockChangedBroadcast(false); 57 } released()58 public void released() { 59 if (DEBUG) { 60 Slog.d(TAG, "last release; broadcasting convenient=true"); 61 } 62 sendLockChangedBroadcast(true); 63 } 64 } 65 UpdateLockService(Context context)66 UpdateLockService(Context context) { 67 mContext = context; 68 mLocks = new LockWatcher(new Handler(), "UpdateLocks"); 69 70 // Consider just-booting to be a reasonable time to allow 71 // interruptions for update installation etc. 72 sendLockChangedBroadcast(true); 73 } 74 sendLockChangedBroadcast(boolean state)75 void sendLockChangedBroadcast(boolean state) { 76 // Safe early during boot because this broadcast only goes to registered receivers. 77 long oldIdent = Binder.clearCallingIdentity(); 78 try { 79 Intent intent = new Intent(UpdateLock.UPDATE_LOCK_CHANGED) 80 .putExtra(UpdateLock.NOW_IS_CONVENIENT, state) 81 .putExtra(UpdateLock.TIMESTAMP, System.currentTimeMillis()) 82 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 83 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 84 } finally { 85 Binder.restoreCallingIdentity(oldIdent); 86 } 87 } 88 89 @Override acquireUpdateLock(IBinder token, String tag)90 public void acquireUpdateLock(IBinder token, String tag) throws RemoteException { 91 if (DEBUG) { 92 Slog.d(TAG, "acquire(" + token + ") by " + makeTag(tag)); 93 } 94 95 mContext.enforceCallingOrSelfPermission(PERMISSION, "acquireUpdateLock"); 96 mLocks.acquire(token, makeTag(tag)); 97 } 98 99 @Override releaseUpdateLock(IBinder token)100 public void releaseUpdateLock(IBinder token) throws RemoteException { 101 if (DEBUG) { 102 Slog.d(TAG, "release(" + token + ')'); 103 } 104 105 mContext.enforceCallingOrSelfPermission(PERMISSION, "releaseUpdateLock"); 106 mLocks.release(token); 107 }; 108 makeTag(String tag)109 private String makeTag(String tag) { 110 return "{tag=" + tag 111 + " uid=" + Binder.getCallingUid() 112 + " pid=" + Binder.getCallingPid() + '}'; 113 } 114 115 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)116 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 117 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 118 mLocks.dump(pw); 119 } 120 } 121