2828import com .google .devtools .mobileharness .platform .android .lightning .apkinstaller .ApkInstallArgs ;
2929import com .google .devtools .mobileharness .platform .android .lightning .apkinstaller .ApkInstaller ;
3030import com .google .devtools .mobileharness .platform .android .systemsetting .AndroidSystemSettingUtil ;
31+ import com .google .devtools .mobileharness .platform .android .xts .common .util .XtsDirUtil ;
3132import com .google .devtools .mobileharness .platform .android .xts .config .DynamicConfig ;
3233import com .google .devtools .mobileharness .platform .android .xts .config .DynamicConfigHandler ;
3334import com .google .devtools .mobileharness .shared .util .file .local .LocalFileUtil ;
4243import com .google .wireless .qa .mobileharness .shared .proto .spec .decorator .AndroidAtsDynamicConfigPusherDecoratorSpec .TestTarget ;
4344import java .io .File ;
4445import java .io .IOException ;
46+ import java .io .InputStream ;
4547import java .net .URI ;
4648import java .net .URISyntaxException ;
4749import java .net .URL ;
50+ import java .nio .file .Files ;
51+ import java .nio .file .Path ;
52+ import java .nio .file .StandardCopyOption ;
4853import java .util .HashMap ;
4954import java .util .List ;
5055import java .util .Locale ;
5156import java .util .Map ;
5257import java .util .Optional ;
58+ import java .util .zip .ZipEntry ;
59+ import java .util .zip .ZipFile ;
5360import javax .annotation .Nullable ;
5461import javax .inject .Inject ;
5562import org .xmlpull .v1 .XmlPullParserException ;
@@ -102,22 +109,25 @@ protected void skippableSetUp(TestInfo testInfo)
102109 AndroidAtsDynamicConfigPusherDecoratorSpec spec =
103110 testInfo .jobInfo ().combinedSpec (this , deviceId );
104111
105- Map <String , String > xtsSuiteInfoMap = xtsSuiteInfoSplitter .split (spec .getXtsSuiteInfo ());
112+ Map <String , String > xtsSuiteInfoMap =
113+ spec .getXtsSuiteInfo ().isEmpty ()
114+ ? new HashMap <>()
115+ : xtsSuiteInfoSplitter .split (spec .getXtsSuiteInfo ());
106116 String suiteName = xtsSuiteInfoMap .get ("suite_name" );
107- if (suiteName == null ) {
108- throw new MobileHarnessException (
109- AndroidErrorId .ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_INVALID_PARAMETER ,
110- "suite_name is missing from xtsSuiteInfo" );
111- }
112117 String suiteVersion = xtsSuiteInfoMap .getOrDefault ("suite_version" , "" );
113118 if (spec .getConfigFilename ().isEmpty ()) {
119+ if (suiteName == null ) {
120+ throw new MobileHarnessException (
121+ AndroidErrorId .ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_INVALID_PARAMETER ,
122+ "suite_name is missing from xtsSuiteInfo" );
123+ }
114124 spec = spec .toBuilder ().setConfigFilename (Ascii .toLowerCase (suiteName )).build ();
115125 }
116126 if (spec .getVersion ().isEmpty ()) {
117127 spec = spec .toBuilder ().setVersion (suiteVersion ).build ();
118128 }
119129
120- File localConfigFile = getLocalConfigFile (spec );
130+ File localConfigFile = getLocalConfigFile (spec , suiteName );
121131 String apfeConfig = fetchApfeConfig (spec , xtsSuiteInfoMap );
122132 File hostFile = mergeConfigFiles (spec , localConfigFile , apfeConfig );
123133 if (spec .getTarget ().equals (TestTarget .DEVICE )) {
@@ -171,30 +181,66 @@ protected void skippableTearDown(TestInfo testInfo)
171181 }
172182 }
173183
174- private File getLocalConfigFile (AndroidAtsDynamicConfigPusherDecoratorSpec spec )
184+ /**
185+ * Gets the local config file.
186+ *
187+ * <p>If {@code extractFromResource} is true, it attempts to extract the dynamic config file from
188+ * the suite's tradefed JAR.
189+ *
190+ * <p>If {@code extractFromResource} is false, it searches for the dynamic config file directly in
191+ * the XTS test directory.
192+ */
193+ private File getLocalConfigFile (
194+ AndroidAtsDynamicConfigPusherDecoratorSpec spec , @ Nullable String suiteName )
175195 throws MobileHarnessException {
196+ String lookupName =
197+ spec .getExtractFromResource ()
198+ ? (spec .getDynamicResourceName ().isEmpty ()
199+ ? spec .getConfigFilename ()
200+ : spec .getDynamicResourceName ())
201+ : (spec .getDynamicConfigName ().isEmpty ()
202+ ? spec .getConfigFilename ()
203+ : spec .getDynamicConfigName ());
204+ String fileName = String .format ("%s.dynamic" , lookupName );
205+
176206 if (spec .getExtractFromResource ()) {
207+ if (suiteName != null && !spec .getXtsTestDir ().isEmpty ()) {
208+ Path xtsRootDir = Path .of (spec .getXtsTestDir ()).getParent ().getParent ();
209+ File toolsDir = XtsDirUtil .getXtsToolsDir (xtsRootDir , suiteName ).toFile ();
210+ File tradefedJar = new File (toolsDir , Ascii .toLowerCase (suiteName ) + "-tradefed.jar" );
211+ if (tradefedJar .exists ()) {
212+ try (ZipFile zipFile = new ZipFile (tradefedJar )) {
213+ ZipEntry entry = zipFile .getEntry (fileName );
214+ if (entry != null ) {
215+ try (InputStream inputStream = zipFile .getInputStream (entry )) {
216+ File localConfigFile = File .createTempFile (lookupName , ".dynamic" );
217+ Files .copy (
218+ inputStream , localConfigFile .toPath (), StandardCopyOption .REPLACE_EXISTING );
219+ return localConfigFile ;
220+ }
221+ }
222+ } catch (IOException e ) {
223+ logger .atWarning ().withCause (e ).log (
224+ "Failed to read from %s" , tradefedJar .getAbsolutePath ());
225+ }
226+ }
227+ }
228+
177229 throw new MobileHarnessException (
178- AndroidErrorId .ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_PARAM_NOT_SUPPORTED ,
179- "Extract from resource is not supported yet." );
230+ AndroidErrorId .ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_LOCAL_CONFIG_NOT_FOUND ,
231+ String . format ( "Fail to find '%s' in tradefed jar" , fileName ) );
180232 }
181233
182- String lookupName =
183- String .format (
184- "%s.dynamic" ,
185- spec .getDynamicConfigName ().isEmpty ()
186- ? spec .getConfigFilename ()
187- : spec .getDynamicConfigName ());
188234 List <File > files = localFileUtil .listFiles (spec .getXtsTestDir (), /* recursively= */ true );
189235 return files .stream ()
190- .filter (file -> file .getName ().equals (lookupName ))
236+ .filter (file -> file .getName ().equals (fileName ))
191237 .findFirst ()
192238 .orElseThrow (
193239 () ->
194240 new MobileHarnessException (
195241 AndroidErrorId
196242 .ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_LOCAL_CONFIG_NOT_FOUND ,
197- String .format ("Config file %s not found." , lookupName )));
243+ String .format ("Config file %s not found." , fileName )));
198244 }
199245
200246 @ Nullable
@@ -204,13 +250,19 @@ private String fetchApfeConfig(
204250 if (!spec .getHasServerSideConfig ()) {
205251 return null ;
206252 }
253+ String suiteName = xtsSuiteInfoMap .get ("suite_name" );
254+ if (suiteName == null ) {
255+ throw new MobileHarnessException (
256+ AndroidErrorId .ANDROID_ATS_DYNAMIC_CONFIG_PUSHER_DECORATOR_INVALID_PARAMETER ,
257+ "suite_name is missing from xtsSuiteInfo" );
258+ }
207259
208260 try {
209261 // TODO: Support to read URL from UrlReplacement.xml. More context in
210262 // com.android.compatibility.common.util.UrlReplacement.java
211263 String requestUrl =
212264 spec .getConfigUrl ()
213- .replace ("{suite-name}" , xtsSuiteInfoMap . get ( "suite_name" ) .toUpperCase (Locale .ROOT ))
265+ .replace ("{suite-name}" , suiteName .toUpperCase (Locale .ROOT ))
214266 .replace ("{module}" , spec .getConfigFilename ())
215267 .replace ("{version}" , spec .getVersion ())
216268 .replace ("{api-key}" , spec .getApiKey ());
0 commit comments