1/*
2 * Copyright (C) 2015 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.messaging.util;
18
19import android.content.Context;
20import android.content.Intent;
21import android.os.Debug;
22import android.os.PowerManager;
23import android.os.Process;
24
25import com.google.common.annotations.VisibleForTesting;
26
27/**
28 * Helper class used to manage wakelock state
29 */
30public class WakeLockHelper {
31    private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
32    private static final boolean VERBOSE = false;
33
34    @VisibleForTesting
35    public static final String EXTRA_CALLING_PID = "pid";
36
37    private final Object mLock = new Object();
38    private final String mWakeLockId;
39    private final int mMyPid;
40
41    private PowerManager.WakeLock mWakeLock;
42
43    public WakeLockHelper(final String wakeLockId) {
44        mWakeLockId = wakeLockId;
45        mMyPid = Process.myPid();
46    }
47
48    /**
49     * Acquire the wakelock
50     */
51    public void acquire(final Context context, final Intent intent, final int opcode) {
52        synchronized (mLock) {
53            if (mWakeLock == null) {
54                if (VERBOSE) {
55                    LogUtil.v(TAG, "initializing wakelock");
56                }
57                final PowerManager pm = (PowerManager)
58                        context.getSystemService(Context.POWER_SERVICE);
59                mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mWakeLockId);
60            }
61        }
62        if (VERBOSE) {
63            LogUtil.v(TAG, "acquiring " + mWakeLockId + " for opcode " + opcode);
64        }
65        mWakeLock.acquire();
66        intent.putExtra(EXTRA_CALLING_PID, mMyPid);
67    }
68
69    /**
70     * Check if wakelock held by this process
71     */
72    public boolean isHeld(final Intent intent) {
73        final boolean respectWakeLock = (mMyPid == intent.getIntExtra(EXTRA_CALLING_PID, -1));
74        return (respectWakeLock && mWakeLock.isHeld());
75    }
76
77    /**
78     * Ensure that wakelock is held by this process
79     */
80    public boolean ensure(final Intent intent, final int opcode) {
81        final boolean respectWakeLock = (mMyPid == intent.getIntExtra(EXTRA_CALLING_PID, -1));
82        if (VERBOSE) {
83            LogUtil.v(TAG, "WakeLockHelper.ensure Intent " + intent + " "
84                    + intent.getAction() + " opcode: " + opcode
85                    + " respectWakeLock " + respectWakeLock);
86        }
87
88        if (respectWakeLock) {
89            final boolean isHeld = (respectWakeLock && isHeld(intent));
90            if (!isHeld) {
91                LogUtil.e(TAG, "WakeLockHelper.ensure called " + intent + " " + intent.getAction()
92                        + " opcode: " + opcode + " sWakeLock: " + mWakeLock + " isHeld: "
93                        + ((mWakeLock == null) ? "(null)" : mWakeLock.isHeld()));
94                if (!Debug.isDebuggerConnected()) {
95                    Assert.fail("WakeLock dropped prior to service starting");
96                }
97            }
98            return true;
99        }
100        return false;
101    }
102
103    /**
104     * Release wakelock (if it is held by this process)
105     */
106    public void release(final Intent intent, final int opcode) {
107        final boolean respectWakeLock = (mMyPid == intent.getIntExtra(EXTRA_CALLING_PID, -1));
108        if (respectWakeLock) {
109            try {
110                mWakeLock.release();
111            } catch (final RuntimeException ex) {
112                LogUtil.e(TAG, "KeepAliveService.onHandleIntent exit crash " + intent + " "
113                        + intent.getAction() + " opcode: " + opcode + " sWakeLock: " + mWakeLock
114                        + " isHeld: " + ((mWakeLock == null) ? "(null)" : mWakeLock.isHeld()));
115                if (!Debug.isDebuggerConnected()) {
116                    Assert.fail("WakeLock no longer held at end of handler");
117                }
118            }
119        }
120    }
121}
122