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 */
16package com.android.car.test;
17
18import android.hardware.automotive.vehicle.V2_0.VehicleApPowerBootupReason;
19import android.hardware.automotive.vehicle.V2_0.VehicleApPowerSetState;
20import android.hardware.automotive.vehicle.V2_0.VehicleApPowerState;
21import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateConfigFlag;
22import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateIndex;
23import android.hardware.automotive.vehicle.V2_0.VehicleApPowerStateShutdownParam;
24import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
25import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
26import android.os.SystemClock;
27import android.test.suitebuilder.annotation.MediumTest;
28
29import com.google.android.collect.Lists;
30
31import com.android.car.vehiclehal.VehiclePropValueBuilder;
32import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
33
34import java.util.ArrayList;
35import java.util.LinkedList;
36import java.util.concurrent.Semaphore;
37import java.util.concurrent.TimeUnit;
38
39@MediumTest
40public class CarPowerManagementTest extends MockedCarTestBase {
41
42    private final PowerStatePropertyHandler mPowerStateHandler = new PowerStatePropertyHandler();
43
44    private void setupPowerPropertyAndStart(boolean allowSleep) {
45        addProperty(VehicleProperty.AP_POWER_STATE, mPowerStateHandler)
46                .setConfigArray(Lists.newArrayList(
47                        allowSleep ? VehicleApPowerStateConfigFlag.ENABLE_DEEP_SLEEP_FLAG : 0));
48
49        addStaticProperty(VehicleProperty.AP_POWER_BOOTUP_REASON,
50                VehiclePropValueBuilder.newBuilder(VehicleProperty.AP_POWER_BOOTUP_REASON)
51                        .addIntValue(VehicleApPowerBootupReason.USER_POWER_ON)
52                        .build());
53
54        reinitializeMockedHal();
55    }
56
57    public void testImmediateShutdown() throws Exception {
58        setupPowerPropertyAndStart(true);
59        assertBootComplete();
60        mPowerStateHandler.sendPowerState(
61                VehicleApPowerState.SHUTDOWN_PREPARE,
62                VehicleApPowerStateShutdownParam.SHUTDOWN_IMMEDIATELY);
63        mPowerStateHandler.waitForStateSetAndGetAll(DEFAULT_WAIT_TIMEOUT_MS,
64                VehicleApPowerSetState.SHUTDOWN_START);
65        mPowerStateHandler.sendPowerState(VehicleApPowerState.ON_FULL, 0);
66    }
67
68    public void testDisplayOnOff() throws Exception {
69        setupPowerPropertyAndStart(true);
70        assertBootComplete();
71        for (int i = 0; i < 2; i++) {
72            mPowerStateHandler.sendPowerState(VehicleApPowerState.ON_DISP_OFF, 0);
73            waitForFakeDisplayState(false);
74            mPowerStateHandler.sendPowerState(VehicleApPowerState.ON_FULL, 0);
75            waitForFakeDisplayState(true);
76        }
77    }
78
79    /* TODO make deep sleep work to test this
80    public void testSleepEntry() throws Exception {
81        assertBootComplete();
82        mPowerStateHandler.sendPowerState(
83                VehicleApPowerState.SHUTDOWN_PREPARE,
84                VehicleApPowerStateShutdownParam.CAN_SLEEP);
85        assertResponse(VehicleApPowerSetState.DEEP_SLEEP_ENTRY, 0);
86        assertResponse(VehicleApPowerSetState.DEEP_SLEEP_EXIT, 0);
87        mPowerStateHandler.sendPowerState(
88                VehicleApPowerState.ON_FULL,
89                0);
90    }*/
91
92    private void assertResponse(int expectedResponseState, int expectedResponseParam)
93            throws Exception {
94        LinkedList<int[]> setEvents = mPowerStateHandler.waitForStateSetAndGetAll(
95                DEFAULT_WAIT_TIMEOUT_MS, expectedResponseState);
96        int[] last = setEvents.getLast();
97        assertEquals(expectedResponseState, last[0]);
98        assertEquals(expectedResponseParam, last[1]);
99    }
100
101    private void assertBootComplete() throws Exception {
102        mPowerStateHandler.waitForSubscription(DEFAULT_WAIT_TIMEOUT_MS);
103        LinkedList<int[]> setEvents = mPowerStateHandler.waitForStateSetAndGetAll(
104                DEFAULT_WAIT_TIMEOUT_MS, VehicleApPowerSetState.BOOT_COMPLETE);
105        int[] first = setEvents.getFirst();
106        assertEquals(VehicleApPowerSetState.BOOT_COMPLETE, first[0]);
107        assertEquals(0, first[1]);
108    }
109
110    private class PowerStatePropertyHandler implements VehicleHalPropertyHandler {
111
112        private int mPowerState = VehicleApPowerState.ON_FULL;
113        private int mPowerParam = 0;
114
115        private final Semaphore mSubscriptionWaitSemaphore = new Semaphore(0);
116        private final Semaphore mSetWaitSemaphore = new Semaphore(0);
117        private LinkedList<int[]> mSetStates = new LinkedList<>();
118
119        @Override
120        public void onPropertySet(VehiclePropValue value) {
121            ArrayList<Integer> v = value.value.int32Values;
122            synchronized (this) {
123                mSetStates.add(new int[] {
124                        v.get(VehicleApPowerStateIndex.STATE),
125                        v.get(VehicleApPowerStateIndex.ADDITIONAL)
126                });
127            }
128            mSetWaitSemaphore.release();
129        }
130
131        @Override
132        public synchronized VehiclePropValue onPropertyGet(VehiclePropValue value) {
133            return VehiclePropValueBuilder.newBuilder(VehicleProperty.AP_POWER_STATE)
134                    .setTimestamp(SystemClock.elapsedRealtimeNanos())
135                    .addIntValue(mPowerState, mPowerParam)
136                    .build();
137        }
138
139        @Override
140        public void onPropertySubscribe(int property, int zones, float sampleRate) {
141            mSubscriptionWaitSemaphore.release();
142        }
143
144        @Override
145        public void onPropertyUnsubscribe(int property) {
146            //ignore
147        }
148
149        private synchronized void setCurrentState(int state, int param) {
150            mPowerState = state;
151            mPowerParam = param;
152        }
153
154        private void waitForSubscription(long timeoutMs) throws Exception {
155            if (!mSubscriptionWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
156                fail("waitForSubscription timeout");
157            }
158        }
159
160        private LinkedList<int[]> waitForStateSetAndGetAll(long timeoutMs, int expectedSet)
161                throws Exception {
162            while (true) {
163                if (!mSetWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) {
164                    fail("waitForStateSetAndGetAll timeout");
165                }
166                synchronized (this) {
167                    boolean found = false;
168                    for (int[] state : mSetStates) {
169                        if (state[0] == expectedSet) {
170                            found = true;
171                        }
172                    }
173                    if (found) {
174                        LinkedList<int[]> res = mSetStates;
175                        mSetStates = new LinkedList<>();
176                        return res;
177                    }
178                }
179            }
180        }
181
182        private void sendPowerState(int state, int param) {
183            getMockedVehicleHal().injectEvent(
184                    VehiclePropValueBuilder.newBuilder(VehicleProperty.AP_POWER_STATE)
185                            .setTimestamp(SystemClock.elapsedRealtimeNanos())
186                            .addIntValue(state, param)
187                            .build());
188        }
189    }
190}
191