| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Constructor; |
| import java.util.HashMap; |
| |
| public class Main { |
| |
| private static final String PROFILE_NAME = "primary.prof"; |
| private static final String APP_DIR_PREFIX = "app_dir_"; |
| private static final String FOREIGN_DEX_PROFILE_DIR = "foreign-dex"; |
| private static final String TEMP_FILE_NAME_PREFIX = "dummy"; |
| private static final String TEMP_FILE_NAME_SUFFIX = "-file"; |
| |
| public static void main(String[] args) throws Exception { |
| File tmpFile = null; |
| File appDir = null; |
| File profileFile = null; |
| File foreignDexProfileDir = null; |
| |
| try { |
| // Create the necessary files layout. |
| tmpFile = createTempFile(); |
| appDir = new File(tmpFile.getParent(), APP_DIR_PREFIX + tmpFile.getName()); |
| appDir.mkdir(); |
| foreignDexProfileDir = new File(tmpFile.getParent(), FOREIGN_DEX_PROFILE_DIR); |
| foreignDexProfileDir.mkdir(); |
| profileFile = createTempFile(); |
| |
| String codePath = System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex.jar"; |
| |
| // Register the app with the runtime |
| VMRuntime.registerAppInfo(profileFile.getPath(), appDir.getPath(), |
| new String[] { codePath }, foreignDexProfileDir.getPath()); |
| |
| testMarkerForForeignDex(foreignDexProfileDir); |
| testMarkerForCodePath(foreignDexProfileDir); |
| testMarkerForApplicationDexFile(foreignDexProfileDir, appDir); |
| } finally { |
| if (tmpFile != null) { |
| tmpFile.delete(); |
| } |
| if (profileFile != null) { |
| profileFile.delete(); |
| } |
| if (foreignDexProfileDir != null) { |
| foreignDexProfileDir.delete(); |
| } |
| if (appDir != null) { |
| appDir.delete(); |
| } |
| } |
| } |
| |
| // Verify we actually create a marker on disk for foreign dex files. |
| private static void testMarkerForForeignDex(File foreignDexProfileDir) throws Exception { |
| String foreignDex = System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex-ex.jar"; |
| loadDexFile(foreignDex); |
| checkMarker(foreignDexProfileDir, foreignDex, /* exists */ true); |
| } |
| |
| // Verify we do not create a marker on disk for dex files path of the code path. |
| private static void testMarkerForCodePath(File foreignDexProfileDir) throws Exception { |
| String codePath = System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex.jar"; |
| loadDexFile(codePath); |
| checkMarker(foreignDexProfileDir, codePath, /* exists */ false); |
| } |
| |
| private static void testMarkerForApplicationDexFile(File foreignDexProfileDir, File appDir) |
| throws Exception { |
| // Copy the -ex jar to the application directory and load it from there. |
| // This will record duplicate class conflicts but we don't care for this use case. |
| File foreignDex = new File(System.getenv("DEX_LOCATION") + "/577-profile-foreign-dex-ex.jar"); |
| File appDex = new File(appDir, "appDex.jar"); |
| try { |
| copyFile(foreignDex, appDex); |
| |
| loadDexFile(appDex.getAbsolutePath()); |
| checkMarker(foreignDexProfileDir, appDex.getAbsolutePath(), /* exists */ false); |
| } finally { |
| if (appDex != null) { |
| appDex.delete(); |
| } |
| } |
| } |
| |
| private static void checkMarker(File foreignDexProfileDir, String dexFile, boolean exists) { |
| File marker = new File(foreignDexProfileDir, dexFile.replace('/', '@')); |
| boolean result_ok = exists ? marker.exists() : !marker.exists(); |
| if (!result_ok) { |
| throw new RuntimeException("Marker test failed for:" + marker.getPath()); |
| } |
| } |
| |
| private static void loadDexFile(String dexFile) throws Exception { |
| Class pathClassLoader = Class.forName("dalvik.system.PathClassLoader"); |
| if (pathClassLoader == null) { |
| throw new RuntimeException("Couldn't find path class loader class"); |
| } |
| Constructor constructor = |
| pathClassLoader.getDeclaredConstructor(String.class, ClassLoader.class); |
| constructor.newInstance( |
| dexFile, ClassLoader.getSystemClassLoader()); |
| } |
| |
| private static class VMRuntime { |
| private static final Method registerAppInfoMethod; |
| static { |
| try { |
| Class c = Class.forName("dalvik.system.VMRuntime"); |
| registerAppInfoMethod = c.getDeclaredMethod("registerAppInfo", |
| String.class, String.class, String[].class, String.class); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static void registerAppInfo(String pkgName, String appDir, |
| String[] codePath, String foreignDexProfileDir) throws Exception { |
| registerAppInfoMethod.invoke(null, pkgName, appDir, codePath, foreignDexProfileDir); |
| } |
| } |
| |
| private static void copyFile(File fromFile, File toFile) throws Exception { |
| FileInputStream in = new FileInputStream(fromFile); |
| FileOutputStream out = new FileOutputStream(toFile); |
| try { |
| byte[] buffer = new byte[4096]; |
| int bytesRead; |
| while ((bytesRead = in.read(buffer)) >= 0) { |
| out.write(buffer, 0, bytesRead); |
| } |
| } finally { |
| out.flush(); |
| try { |
| out.getFD().sync(); |
| } catch (IOException e) { |
| } |
| out.close(); |
| in.close(); |
| } |
| } |
| |
| private static File createTempFile() throws Exception { |
| try { |
| return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); |
| } catch (IOException e) { |
| System.setProperty("java.io.tmpdir", "/data/local/tmp"); |
| try { |
| return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); |
| } catch (IOException e2) { |
| System.setProperty("java.io.tmpdir", "/sdcard"); |
| return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX); |
| } |
| } |
| } |
| } |