1 /*
2  * Copyright (C) 2020 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.usage;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
21 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
22 
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.fail;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.ArgumentMatchers.anyInt;
27 import static org.mockito.Mockito.mock;
28 
29 import android.app.ActivityManager;
30 import android.app.IActivityManager;
31 import android.app.usage.UsageEvents;
32 import android.app.usage.UsageStatsManagerInternal;
33 import android.content.Context;
34 import android.os.RemoteException;
35 
36 import androidx.test.runner.AndroidJUnit4;
37 
38 import com.android.server.LocalServices;
39 
40 import org.junit.After;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.mockito.Mock;
45 import org.mockito.MockitoSession;
46 import org.mockito.quality.Strictness;
47 
48 import java.util.concurrent.CountDownLatch;
49 import java.util.concurrent.TimeUnit;
50 
51 @RunWith(AndroidJUnit4.class)
52 public class UsageStatsServiceTest {
53     private static final long TIMEOUT = 5000;
54 
55     private UsageStatsService mService;
56 
57     private MockitoSession mMockingSession;
58     @Mock
59     private Context mContext;
60 
61     private static class TestInjector extends UsageStatsService.Injector {
getAppStandbyController(Context context)62         AppStandbyInternal getAppStandbyController(Context context) {
63             return mock(AppStandbyInternal.class);
64         }
65     }
66 
67     @Before
setUp()68     public void setUp() {
69         mMockingSession = mockitoSession()
70                 .initMocks(this)
71                 .strictness(Strictness.LENIENT)
72                 .startMocking();
73         IActivityManager activityManager = ActivityManager.getService();
74         spyOn(activityManager);
75         try {
76             doNothing().when(activityManager).registerUidObserver(any(), anyInt(), anyInt(), any());
77         } catch (RemoteException e) {
78             fail("registerUidObserver threw exception: " + e.getMessage());
79         }
80         mService = new UsageStatsService(mContext, new TestInjector());
81         spyOn(mService);
82         doNothing().when(mService).publishBinderServices();
83         mService.onStart();
84     }
85 
86     @After
tearDown()87     public void tearDown() {
88         if (mMockingSession != null) {
89             mMockingSession.finishMocking();
90         }
91     }
92 
93     @Test
testUsageEventListener()94     public void testUsageEventListener() throws Exception {
95         TestUsageEventListener listener = new TestUsageEventListener();
96         UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class);
97         usmi.registerListener(listener);
98 
99         UsageEvents.Event event = new UsageEvents.Event(UsageEvents.Event.CONFIGURATION_CHANGE, 10);
100         usmi.reportEvent("com.android.test", 10, event.getEventType());
101         listener.setExpectation(10, event);
102         listener.mCountDownLatch.await(TIMEOUT, TimeUnit.MILLISECONDS);
103 
104         usmi.unregisterListener(listener);
105         listener.reset();
106 
107         usmi.reportEvent("com.android.test", 0, UsageEvents.Event.CHOOSER_ACTION);
108         Thread.sleep(TIMEOUT);
109         assertNull(listener.mLastReceivedEvent);
110     }
111 
112     private static class TestUsageEventListener implements
113             UsageStatsManagerInternal.UsageEventListener {
114         UsageEvents.Event mLastReceivedEvent;
115         int mLastReceivedUserId;
116         UsageEvents.Event mExpectedEvent;
117         int mExpectedUserId;
118         CountDownLatch mCountDownLatch;
119 
120         @Override
onUsageEvent(int userId, UsageEvents.Event event)121         public void onUsageEvent(int userId, UsageEvents.Event event) {
122             mLastReceivedUserId = userId;
123             mLastReceivedEvent = event;
124             if (mCountDownLatch != null && userId == mExpectedUserId
125                     && event.getEventType() == mExpectedEvent.getEventType()) {
126                 mCountDownLatch.countDown();
127             }
128         }
129 
setExpectation(int userId, UsageEvents.Event event)130         private void setExpectation(int userId, UsageEvents.Event event) {
131             mExpectedUserId = userId;
132             mExpectedEvent = event;
133             mCountDownLatch = new CountDownLatch(1);
134         }
135 
reset()136         private void reset() {
137             mLastReceivedUserId = mExpectedUserId = -1;
138             mLastReceivedEvent = mExpectedEvent = null;
139             mCountDownLatch = null;
140         }
141     }
142 }
143