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 com.android.server;
188662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
198662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.content.Context;
208662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.content.Intent;
218662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.content.pm.PackageManager;
228662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.os.Binder;
238662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.os.Handler;
248662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.os.IBinder;
258662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.os.IUpdateLock;
268662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.os.RemoteException;
278662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.os.TokenWatcher;
288662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.os.UpdateLock;
295ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle;
308662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport android.util.Slog;
318662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
32fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkeyimport com.android.internal.util.DumpUtils;
33fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkey
348662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport java.io.FileDescriptor;
358662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tateimport java.io.PrintWriter;
368662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
378662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tatepublic class UpdateLockService extends IUpdateLock.Stub {
388662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    static final boolean DEBUG = false;
398662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    static final String TAG = "UpdateLockService";
408662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
418662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    // signatureOrSystem required to use update locks
428662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    static final String PERMISSION = "android.permission.UPDATE_LOCK";
438662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
448662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    Context mContext;
458662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    LockWatcher mLocks;
468662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
478662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    class LockWatcher extends TokenWatcher {
488662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        LockWatcher(Handler h, String tag) {
498662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            super(h, tag);
508662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        }
518662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
528662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        public void acquired() {
538662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            if (DEBUG) {
548662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate                Slog.d(TAG, "first acquire; broadcasting convenient=false");
558662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            }
568662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            sendLockChangedBroadcast(false);
578662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        }
588662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        public void released() {
598662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            if (DEBUG) {
608662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate                Slog.d(TAG, "last release; broadcasting convenient=true");
618662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            }
628662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            sendLockChangedBroadcast(true);
638662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        }
648662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    }
658662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
668662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    UpdateLockService(Context context) {
678662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        mContext = context;
688662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        mLocks = new LockWatcher(new Handler(), "UpdateLocks");
698662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
708662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        // Consider just-booting to be a reasonable time to allow
718662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        // interruptions for update installation etc.
728662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        sendLockChangedBroadcast(true);
738662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    }
748662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
758662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    void sendLockChangedBroadcast(boolean state) {
768662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        // Safe early during boot because this broadcast only goes to registered receivers.
778662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        long oldIdent = Binder.clearCallingIdentity();
788662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        try {
798662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            Intent intent = new Intent(UpdateLock.UPDATE_LOCK_CHANGED)
808662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate                    .putExtra(UpdateLock.NOW_IS_CONVENIENT, state)
818662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate                    .putExtra(UpdateLock.TIMESTAMP, System.currentTimeMillis())
825bb59daf42fb24c1131effd4265c2386304fecebChristopher Tate                    .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
835ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
848662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        } finally {
858662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            Binder.restoreCallingIdentity(oldIdent);
868662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        }
878662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    }
888662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
898662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    @Override
908662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    public void acquireUpdateLock(IBinder token, String tag) throws RemoteException {
918662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        if (DEBUG) {
928662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            Slog.d(TAG, "acquire(" + token + ") by " + makeTag(tag));
938662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        }
948662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
958662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        mContext.enforceCallingOrSelfPermission(PERMISSION, "acquireUpdateLock");
968662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        mLocks.acquire(token, makeTag(tag));
978662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    }
988662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
998662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    @Override
1008662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    public void releaseUpdateLock(IBinder token) throws RemoteException {
1018662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        if (DEBUG) {
1028662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate            Slog.d(TAG, "release(" + token + ')');
1038662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        }
1048662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
1058662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        mContext.enforceCallingOrSelfPermission(PERMISSION, "releaseUpdateLock");
1068662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        mLocks.release(token);
1078662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    };
1088662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
1098662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    private String makeTag(String tag) {
1108662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        return "{tag=" + tag
1118662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate                + " uid=" + Binder.getCallingUid()
1128662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate                + " pid=" + Binder.getCallingPid() + '}';
1138662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    }
1148662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate
1158662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    @Override
1168662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
117fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkey        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1188662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate        mLocks.dump(pw);
1198662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate    }
1208662cab5c6a01ea5c426512e6f6d2cf3e158aea0Christopher Tate}
121