1 /*
2  * Copyright (C) 2021 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.app;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNull;
23 import static org.junit.Assert.assertTrue;
24 
25 import android.app.GameManager;
26 import android.content.Context;
27 import android.platform.test.annotations.Presubmit;
28 import android.util.AtomicFile;
29 import android.util.Log;
30 
31 import androidx.test.InstrumentationRegistry;
32 import androidx.test.filters.SmallTest;
33 import androidx.test.runner.AndroidJUnit4;
34 
35 import com.android.server.app.GameManagerService.GamePackageConfiguration;
36 import com.android.server.app.GameManagerService.GamePackageConfiguration.GameModeConfiguration;
37 
38 import org.junit.After;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 
42 import java.io.File;
43 import java.io.FileOutputStream;
44 import java.io.IOException;
45 
46 @RunWith(AndroidJUnit4.class)
47 @SmallTest
48 @Presubmit
49 public class GameManagerServiceSettingsTests {
50 
51     private static final String TAG = "GameServiceSettingsTests";
52     private static final String PACKAGE_NAME_1 = "com.android.app1";
53     private static final String PACKAGE_NAME_2 = "com.android.app2";
54     private static final String PACKAGE_NAME_3 = "com.android.app3";
55     private static final String PACKAGE_NAME_4 = "com.android.app4";
56 
57 
writeFile(File file, byte[] data)58     private void writeFile(File file, byte[] data) {
59         file.mkdirs();
60         try {
61             AtomicFile aFile = new AtomicFile(file);
62             FileOutputStream fos = aFile.startWrite();
63             fos.write(data);
64             aFile.finishWrite(fos);
65         } catch (IOException ioe) {
66             Log.e(TAG, "Cannot write file " + file.getPath());
67         }
68     }
69 
writeGameServiceXml()70     private void writeGameServiceXml() {
71         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(),
72                         "system/game-manager-service.xml"),
73                 ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
74                         + "<packages>"
75                         + "\n" // app1: no package config setting
76                         + "\n" // app2: performance mode is selected with override
77                         + "  <package name=\"com.android.app2\" gameMode=\"2\">\n"
78                         + "     <gameModeConfig gameMode=\"2\" scaling=\"0.99\" "
79                         + "useAngle=\"true\" fps=\"90\" loadingBoost=\"123\"></gameModeConfig>\n"
80                         + "     <gameModeConfig gameMode=\"3\"></gameModeConfig>\n"
81                         + "  </package>"
82                         + "\n" // app3: only battery mode is selected
83                         + "  <package name=\"com.android.app3\" gameMode=\"3\">\n"
84                         + "  </package>"
85                         + "\n" // app4: no game mode selected but custom game mode config
86                         + "  <package name=\"com.android.app4\">\n"
87                         + "     <gameModeConfig gameMode=\"4\" scaling=\"0.4\" "
88                         + "fps=\"30\"></gameModeConfig>\n"
89                         + "  </package>"
90                         + "\n"
91                         + "</packages>\n").getBytes());
92     }
93 
deleteSystemFolder()94     private void deleteSystemFolder() {
95         File systemFolder = new File(InstrumentationRegistry.getContext().getFilesDir(), "system");
96         deleteFolder(systemFolder);
97     }
98 
deleteFolder(File folder)99     private static void deleteFolder(File folder) {
100         File[] files = folder.listFiles();
101         if (files != null) {
102             for (File file : files) {
103                 deleteFolder(file);
104             }
105         }
106         folder.delete();
107     }
108 
writeOldFiles()109     private void writeOldFiles() {
110         deleteSystemFolder();
111         writeGameServiceXml();
112     }
113 
114     @After
tearDown()115     public void tearDown() throws Exception {
116         deleteFolder(InstrumentationRegistry.getTargetContext().getFilesDir());
117     }
118 
119     @Test
testReadGameServiceSettings()120     public void testReadGameServiceSettings() {
121         writeOldFiles();
122         final Context context = InstrumentationRegistry.getContext();
123         GameManagerSettings settings = new GameManagerSettings(context.getFilesDir());
124         assertTrue(settings.readPersistentDataLocked());
125 
126         // test game modes
127         assertEquals(GameManager.GAME_MODE_STANDARD, settings.getGameModeLocked(PACKAGE_NAME_1));
128         assertEquals(GameManager.GAME_MODE_PERFORMANCE, settings.getGameModeLocked(PACKAGE_NAME_2));
129         assertEquals(GameManager.GAME_MODE_BATTERY, settings.getGameModeLocked(PACKAGE_NAME_3));
130         assertEquals(GameManager.GAME_MODE_STANDARD, settings.getGameModeLocked(PACKAGE_NAME_4));
131 
132         // test game mode configs
133         assertNull(settings.getConfigOverride(PACKAGE_NAME_1));
134         assertNull(settings.getConfigOverride(PACKAGE_NAME_3));
135         GamePackageConfiguration config = settings.getConfigOverride(PACKAGE_NAME_2);
136         assertNotNull(config);
137 
138         assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_STANDARD));
139         final GameModeConfiguration performanceConfig = config.getGameModeConfiguration(
140                 GameManager.GAME_MODE_PERFORMANCE);
141         assertNotNull(performanceConfig);
142         assertEquals(performanceConfig.getScaling(), 0.99, 0.01f);
143         assertEquals(performanceConfig.getLoadingBoostDuration(), 123);
144         assertEquals(performanceConfig.getFpsStr(), "90");
145         assertTrue(performanceConfig.getUseAngle());
146         final GameModeConfiguration batteryConfig = config.getGameModeConfiguration(
147                 GameManager.GAME_MODE_BATTERY);
148         assertNotNull(batteryConfig);
149         assertEquals(batteryConfig.getScaling(), GameModeConfiguration.DEFAULT_SCALING, 0.01f);
150         assertEquals(batteryConfig.getLoadingBoostDuration(),
151                 GameModeConfiguration.DEFAULT_LOADING_BOOST_DURATION);
152         assertEquals(batteryConfig.getFpsStr(), GameModeConfiguration.DEFAULT_FPS);
153         assertFalse(batteryConfig.getUseAngle());
154 
155         config = settings.getConfigOverride(PACKAGE_NAME_4);
156         assertNotNull(config);
157         GameModeConfiguration customConfig = config.getGameModeConfiguration(
158                 GameManager.GAME_MODE_CUSTOM);
159         assertNotNull(customConfig);
160         assertEquals(customConfig.getScaling(), 0.4f, 0.1f);
161         assertEquals(customConfig.getFps(), 30);
162     }
163 
164     @Test
testReadGameServiceSettings_invalidConfigAttributes()165     public void testReadGameServiceSettings_invalidConfigAttributes() {
166         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(),
167                         "system/game-manager-service.xml"),
168                 ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
169                         + "<packages>\n"
170                         + "  <package name=\"com.android.app1\" gameMode=\"1\">\n"
171                         + "     <gameModeConfig gameMode=\"3\" scaling=\"invalid\" "
172                         + "useAngle=\"invalid\" fps=\"invalid\" "
173                         + "loadingBoost=\"invalid\"></gameModeConfig>\n"
174                         + "  </package>\n"
175                         + "</packages>\n").getBytes());
176         final Context context = InstrumentationRegistry.getContext();
177         GameManagerSettings settings = new GameManagerSettings(context.getFilesDir());
178         assertTrue(settings.readPersistentDataLocked());
179 
180         final GamePackageConfiguration config = settings.getConfigOverride(PACKAGE_NAME_1);
181         assertNotNull(config);
182         final GameModeConfiguration batteryConfig = config.getGameModeConfiguration(
183                 GameManager.GAME_MODE_BATTERY);
184         assertNotNull(batteryConfig);
185         assertEquals(batteryConfig.getScaling(), GameModeConfiguration.DEFAULT_SCALING, 0.01f);
186         assertEquals(batteryConfig.getLoadingBoostDuration(),
187                 GameModeConfiguration.DEFAULT_LOADING_BOOST_DURATION);
188         assertEquals(batteryConfig.getFpsStr(), "invalid");
189         assertFalse(batteryConfig.getUseAngle());
190     }
191 
192     @Test
testReadGameServiceSettings_invalidTags()193     public void testReadGameServiceSettings_invalidTags() {
194         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(),
195                         "system/game-manager-service.xml"),
196                 ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
197                         + "<packages>"
198                         + "\n" // missing package name
199                         + "  <package gameMode=\"1\">\n"
200                         + "  </package>"
201                         + "\n" // app2 with unknown sub element
202                         + "  <package name=\"com.android.app2\" gameMode=\"2\">\n"
203                         + "     <unknown></unknown>"
204                         + "     <gameModeConfig gameMode=\"3\" fps=\"90\"></gameModeConfig>\n"
205                         + "     foo bar"
206                         + "  </package>"
207                         + "\n" // unknown package element
208                         + "  <unknownTag></unknownTag>\n"
209                         + "    foo bar"
210                         + "\n" // app3 after unknown element
211                         + "  <package name=\"com.android.app3\" gameMode=\"3\">\n"
212                         + "  </package>\n"
213                         + "</packages>\n").getBytes());
214         final Context context = InstrumentationRegistry.getContext();
215         GameManagerSettings settings = new GameManagerSettings(context.getFilesDir());
216         assertTrue(settings.readPersistentDataLocked());
217         assertEquals(1, settings.getGameModeLocked(PACKAGE_NAME_1));
218         assertEquals(2, settings.getGameModeLocked(PACKAGE_NAME_2));
219         assertEquals(3, settings.getGameModeLocked(PACKAGE_NAME_3));
220 
221         final GamePackageConfiguration config = settings.getConfigOverride(PACKAGE_NAME_2);
222         assertNotNull(config);
223         final GameModeConfiguration batteryConfig = config.getGameModeConfiguration(
224                 GameManager.GAME_MODE_BATTERY);
225         assertNotNull(batteryConfig);
226         assertEquals(batteryConfig.getFpsStr(), "90");
227     }
228 
229 
230     @Test
testWriteGameServiceSettings()231     public void testWriteGameServiceSettings() {
232         final Context context = InstrumentationRegistry.getContext();
233         GameManagerSettings settings = new GameManagerSettings(context.getFilesDir());
234 
235         // set package settings and write out to file
236         settings.setGameModeLocked(PACKAGE_NAME_1, GameManager.GAME_MODE_BATTERY);
237         settings.setGameModeLocked(PACKAGE_NAME_2, GameManager.GAME_MODE_PERFORMANCE);
238         settings.setGameModeLocked(PACKAGE_NAME_3, GameManager.GAME_MODE_STANDARD);
239 
240         // set config for app2
241         GamePackageConfiguration config = new GamePackageConfiguration(PACKAGE_NAME_2);
242         GameModeConfiguration performanceConfig = config.getOrAddDefaultGameModeConfiguration(
243                 GameManager.GAME_MODE_PERFORMANCE);
244         performanceConfig.setLoadingBoostDuration(321);
245         performanceConfig.setScaling(0.66f);
246         performanceConfig.setUseAngle(true);
247         performanceConfig.setFpsStr("60");
248         GameModeConfiguration batteryConfig = config.getOrAddDefaultGameModeConfiguration(
249                 GameManager.GAME_MODE_BATTERY);
250         batteryConfig.setScaling(0.77f);
251         settings.setConfigOverride(PACKAGE_NAME_2, config);
252 
253         // set config for app4
254         config = new GamePackageConfiguration(PACKAGE_NAME_4);
255         GameModeConfiguration customConfig = config.getOrAddDefaultGameModeConfiguration(
256                 GameManager.GAME_MODE_CUSTOM);
257         customConfig.setScaling(0.4f);
258         customConfig.setFpsStr("30");
259         settings.setConfigOverride(PACKAGE_NAME_4, config);
260 
261         settings.writePersistentDataLocked();
262 
263         // clear the settings in memory
264         settings.removeGame(PACKAGE_NAME_1);
265         settings.removeGame(PACKAGE_NAME_2);
266         settings.removeGame(PACKAGE_NAME_3);
267         settings.removeGame(PACKAGE_NAME_4);
268 
269         // read back in and verify
270         assertTrue(settings.readPersistentDataLocked());
271         assertEquals(3, settings.getGameModeLocked(PACKAGE_NAME_1));
272         assertEquals(2, settings.getGameModeLocked(PACKAGE_NAME_2));
273         assertEquals(1, settings.getGameModeLocked(PACKAGE_NAME_3));
274         assertEquals(1, settings.getGameModeLocked(PACKAGE_NAME_4));
275 
276         config = settings.getConfigOverride(PACKAGE_NAME_1);
277         assertNull(config);
278         config = settings.getConfigOverride(PACKAGE_NAME_2);
279         assertNotNull(config);
280         batteryConfig = config.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY);
281         assertNotNull(batteryConfig);
282         assertEquals(batteryConfig.getScaling(), 0.77f, 0.01f);
283         assertEquals(batteryConfig.getLoadingBoostDuration(),
284                 GameModeConfiguration.DEFAULT_LOADING_BOOST_DURATION);
285         assertEquals(batteryConfig.getFpsStr(), GameModeConfiguration.DEFAULT_FPS);
286         assertFalse(batteryConfig.getUseAngle());
287 
288         performanceConfig = config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE);
289         assertNotNull(performanceConfig);
290         assertEquals(performanceConfig.getScaling(), 0.66f, 0.01f);
291         assertEquals(performanceConfig.getLoadingBoostDuration(), 321);
292         assertEquals(performanceConfig.getFpsStr(), "60");
293         assertTrue(performanceConfig.getUseAngle());
294 
295         config = settings.getConfigOverride(PACKAGE_NAME_4);
296         assertNotNull(config);
297         customConfig = config.getGameModeConfiguration(GameManager.GAME_MODE_CUSTOM);
298         assertNotNull(customConfig);
299         assertEquals(customConfig.getScaling(), 0.4f, 0.1f);
300         assertEquals(customConfig.getFps(), 30);
301         assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE));
302         assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY));
303     }
304 }
305