• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.launcher3.testing;
18 
19 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
20 
21 import android.content.Context;
22 import android.os.Binder;
23 import android.os.Bundle;
24 import android.system.Os;
25 import android.view.View;
26 
27 import androidx.annotation.Keep;
28 
29 import com.android.launcher3.LauncherAppState;
30 import com.android.launcher3.LauncherSettings;
31 
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.LinkedList;
35 import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.TimeUnit;
37 
38 /**
39  * Class to handle requests from tests, including debug ones.
40  */
41 public class DebugTestInformationHandler extends TestInformationHandler {
42     private static LinkedList sLeaks;
43     private static Collection<String> sEvents;
44 
DebugTestInformationHandler(Context context)45     public DebugTestInformationHandler(Context context) {
46         init(context);
47     }
48 
runGcAndFinalizersSync()49     private static void runGcAndFinalizersSync() {
50         Runtime.getRuntime().gc();
51         Runtime.getRuntime().runFinalization();
52 
53         final CountDownLatch fence = new CountDownLatch(1);
54         createFinalizationObserver(fence);
55         try {
56             do {
57                 Runtime.getRuntime().gc();
58                 Runtime.getRuntime().runFinalization();
59             } while (!fence.await(100, TimeUnit.MILLISECONDS));
60         } catch (InterruptedException ex) {
61             throw new RuntimeException(ex);
62         }
63     }
64 
65     // Create the observer in the scope of a method to minimize the chance that
66     // it remains live in a DEX/machine register at the point of the fence guard.
67     // This must be kept to avoid R8 inlining it.
68     @Keep
createFinalizationObserver(CountDownLatch fence)69     private static void createFinalizationObserver(CountDownLatch fence) {
70         new Object() {
71             @Override
72             protected void finalize() throws Throwable {
73                 try {
74                     fence.countDown();
75                 } finally {
76                     super.finalize();
77                 }
78             }
79         };
80     }
81 
82     @Override
call(String method)83     public Bundle call(String method) {
84         final Bundle response = new Bundle();
85         switch (method) {
86             case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
87                 return getLauncherUIProperty(Bundle::putInt,
88                         l -> l.getAppsView().getAppsStore().getDeferUpdatesFlags());
89             }
90 
91             case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
92                 TestProtocol.sDebugTracing = true;
93                 return response;
94 
95             case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
96                 TestProtocol.sDebugTracing = false;
97                 return response;
98 
99             case TestProtocol.REQUEST_PID: {
100                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, Os.getpid());
101                 return response;
102             }
103 
104             case TestProtocol.REQUEST_FORCE_GC: {
105                 runGcAndFinalizersSync();
106                 return response;
107             }
108 
109             case TestProtocol.REQUEST_VIEW_LEAK: {
110                 if (sLeaks == null) sLeaks = new LinkedList();
111                 sLeaks.add(new View(mContext));
112                 sLeaks.add(new View(mContext));
113                 return response;
114             }
115 
116             case TestProtocol.REQUEST_START_EVENT_LOGGING: {
117                 sEvents = new ArrayList<>();
118                 TestLogging.setEventConsumer(
119                         (sequence, event) -> {
120                             final Collection<String> events = sEvents;
121                             if (events != null) {
122                                 synchronized (events) {
123                                     events.add(sequence + '/' + event);
124                                 }
125                             }
126                         });
127                 return response;
128             }
129 
130             case TestProtocol.REQUEST_STOP_EVENT_LOGGING: {
131                 TestLogging.setEventConsumer(null);
132                 sEvents = null;
133                 return response;
134             }
135 
136             case TestProtocol.REQUEST_GET_TEST_EVENTS: {
137                 if (sEvents == null) {
138                     // sEvents can be null if Launcher died and restarted after
139                     // REQUEST_START_EVENT_LOGGING.
140                     return response;
141                 }
142 
143                 synchronized (sEvents) {
144                     response.putStringArrayList(
145                             TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
146                 }
147                 return response;
148             }
149 
150             case TestProtocol.REQUEST_CLEAR_DATA: {
151                 final long identity = Binder.clearCallingIdentity();
152                 try {
153                     LauncherSettings.Settings.call(mContext.getContentResolver(),
154                             LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
155                     MAIN_EXECUTOR.submit(() ->
156                             LauncherAppState.getInstance(mContext).getModel().forceReload());
157                     return response;
158                 } finally {
159                     Binder.restoreCallingIdentity(identity);
160                 }
161             }
162 
163             default:
164                 return super.call(method);
165         }
166     }
167 }
168