UpdateLockService.java revision 5ac72a29593ab9a20337a2225df52bdf4754be02
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
17package com.android.server;
18
19import android.content.Context;
20import android.content.Intent;
21import android.content.pm.PackageManager;
22import android.os.Binder;
23import android.os.Handler;
24import android.os.IBinder;
25import android.os.IUpdateLock;
26import android.os.RemoteException;
27import android.os.SystemClock;
28import android.os.TokenWatcher;
29import android.os.UpdateLock;
30import android.os.UserHandle;
31import android.util.Slog;
32
33import java.io.FileDescriptor;
34import java.io.PrintWriter;
35
36public class UpdateLockService extends IUpdateLock.Stub {
37    static final boolean DEBUG = false;
38    static final String TAG = "UpdateLockService";
39
40    // signatureOrSystem required to use update locks
41    static final String PERMISSION = "android.permission.UPDATE_LOCK";
42
43    Context mContext;
44    LockWatcher mLocks;
45
46    class LockWatcher extends TokenWatcher {
47        LockWatcher(Handler h, String tag) {
48            super(h, tag);
49        }
50
51        public void acquired() {
52            if (DEBUG) {
53                Slog.d(TAG, "first acquire; broadcasting convenient=false");
54            }
55            sendLockChangedBroadcast(false);
56        }
57        public void released() {
58            if (DEBUG) {
59                Slog.d(TAG, "last release; broadcasting convenient=true");
60            }
61            sendLockChangedBroadcast(true);
62        }
63    }
64
65    UpdateLockService(Context context) {
66        mContext = context;
67        mLocks = new LockWatcher(new Handler(), "UpdateLocks");
68
69        // Consider just-booting to be a reasonable time to allow
70        // interruptions for update installation etc.
71        sendLockChangedBroadcast(true);
72    }
73
74    void sendLockChangedBroadcast(boolean state) {
75        // Safe early during boot because this broadcast only goes to registered receivers.
76        long oldIdent = Binder.clearCallingIdentity();
77        try {
78            Intent intent = new Intent(UpdateLock.UPDATE_LOCK_CHANGED)
79                    .putExtra(UpdateLock.NOW_IS_CONVENIENT, state)
80                    .putExtra(UpdateLock.TIMESTAMP, System.currentTimeMillis())
81                    .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
82            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
83        } finally {
84            Binder.restoreCallingIdentity(oldIdent);
85        }
86    }
87
88    @Override
89    public void acquireUpdateLock(IBinder token, String tag) throws RemoteException {
90        if (DEBUG) {
91            Slog.d(TAG, "acquire(" + token + ") by " + makeTag(tag));
92        }
93
94        mContext.enforceCallingOrSelfPermission(PERMISSION, "acquireUpdateLock");
95        mLocks.acquire(token, makeTag(tag));
96    }
97
98    @Override
99    public void releaseUpdateLock(IBinder token) throws RemoteException {
100        if (DEBUG) {
101            Slog.d(TAG, "release(" + token + ')');
102        }
103
104        mContext.enforceCallingOrSelfPermission(PERMISSION, "releaseUpdateLock");
105        mLocks.release(token);
106    };
107
108    private String makeTag(String tag) {
109        return "{tag=" + tag
110                + " uid=" + Binder.getCallingUid()
111                + " pid=" + Binder.getCallingPid() + '}';
112    }
113
114    @Override
115    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
116        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
117                != PackageManager.PERMISSION_GRANTED) {
118            pw.println("Permission Denial: can't dump update lock service from from pid="
119                    + Binder.getCallingPid()
120                    + ", uid=" + Binder.getCallingUid());
121            return;
122        }
123
124        mLocks.dump(pw);
125    }
126}
127