/* * Copyright 2014-present Facebook, Inc. * * 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. */ package com.facebook.buck.android; import static com.facebook.buck.android.exopackage.ExopackageInstaller.NATIVE_LIB_PATTERN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import com.facebook.buck.android.exopackage.ExopackageInstaller; import com.facebook.buck.android.exopackage.PackageInfo; import com.facebook.buck.android.exopackage.RealExopackageDevice; import com.facebook.buck.testutil.FakeProjectFilesystem; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Optional; import java.util.regex.Matcher; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @SuppressWarnings("PMD.AddEmptyString") public class ExopackageInstallerTest { @Rule public ExpectedException thrown = ExpectedException.none(); @Test public void testScanSecondaryDexDir() throws Exception { String output = "exopackage_temp-secondary-abcdefg.dex.jar-588103794.tmp\r\n" + "lock\r\n" + "metadata.txt\r\n" + "secondary-0fa1f9cfb3c0effa8000d2d86d267985b158df9f.dex.jar\r\n" + "secondary-07fc80d2de21bd1dd57be0728fdb6c14190c3386.dex.jar\r\n" + "secondary-2add18058985241f7999eb026868cebb9ef63379.dex.jar\r\n" + ""; ImmutableSet<String> requiredHashes = ImmutableSet.of( "0fa1f9cfb3c0effa8000d2d86d267985b158df9f", "2add18058985241f7999eb026868cebb9ef63379", "97d21318d1d5dd298f6ee932916c6ee949fe760e"); ImmutableSet.Builder<String> foundHashesBuilder = ImmutableSet.builder(); ImmutableSet.Builder<String> toDeleteBuilder = ImmutableSet.builder(); ExopackageInstaller.processLsOutput( output, ExopackageInstaller.DEX_FILE_PATTERN, requiredHashes, foundHashesBuilder, toDeleteBuilder); assertEquals( ImmutableSet.of( "0fa1f9cfb3c0effa8000d2d86d267985b158df9f", "2add18058985241f7999eb026868cebb9ef63379"), foundHashesBuilder.build()); assertEquals( ImmutableSet.of( "exopackage_temp-secondary-abcdefg.dex.jar-588103794.tmp", "metadata.txt", "secondary-07fc80d2de21bd1dd57be0728fdb6c14190c3386.dex.jar"), toDeleteBuilder.build()); } @Test public void testParsePathAndPackageInfo() { String lines = "package:/data/app/com.facebook.katana-1.apk\r\n" + " Package [com.facebook.katana] (4229ce68):\r\n" + " userId=10145 gids=[1028, 1015, 3003]\r\n" + " pkg=Package{42690b80 com.facebook.katana}\r\n" + " codePath=/data/app/com.facebook.katana-1.apk\r\n" + " resourcePath=/data/app/com.facebook.katana-1.apk\r\n" + " nativeLibraryPath=/data/app-lib/com.facebook.katana-1\r\n" + " versionCode=1640376 targetSdk=14\r\n" + " versionName=8.0.0.0.23\r\n" + ""; Optional<PackageInfo> optionalInfo = ExopackageInstaller.parsePathAndPackageInfo("com.facebook.katana", lines); assertTrue(optionalInfo.isPresent()); PackageInfo info = optionalInfo.get(); assertEquals("/data/app/com.facebook.katana-1.apk", info.apkPath); assertEquals("/data/app-lib/com.facebook.katana-1", info.nativeLibPath); assertEquals("1640376", info.versionCode); } @Test public void testParsePathAndPackageInfoOnLollipop() { String lines = "package:/data/app/com.facebook.buck.android.agent-1.apk\r\n" + " Package [com.facebook.buck.android.agent] (3f784d07):\r\n" + " userId=10062 gids=[]\r\n" + " pkg=Package{81b1e34 com.facebook.buck.android.agent}\r\n" + " codePath=/data/app/com.facebook.buck.android.agent-1\r\n" + " resourcePath=/data/app/com.facebook.buck.android.agent-1\r\n" + " legacyNativeLibraryDir=/data/app/com.facebook.buck.android.agent-1/lib\r\n" + " primaryCpuAbi=armeabi-v7a\r\n" + " secondaryCpuAbi=null\r\n" + " versionCode=3 targetSdk=19\r\n" + " versionName=3\r\n" + ""; Optional<PackageInfo> optionalInfo = ExopackageInstaller.parsePathAndPackageInfo("com.facebook.buck.android.agent", lines); assertTrue(optionalInfo.isPresent()); PackageInfo info = optionalInfo.get(); assertEquals("/data/app/com.facebook.buck.android.agent-1/base.apk", info.apkPath); assertEquals("/data/app/com.facebook.buck.android.agent-1/lib", info.nativeLibPath); assertEquals("3", info.versionCode); } @Test public void testParseOnlyPackageInfo() { String lines = "1\r\n" + " Package [com.facebook.katana] (4229ce68):\r\n" + " userId=10145 gids=[1028, 1015, 3003]\r\n" + " pkg=Package{42690b80 com.facebook.katana}\r\n" + " codePath=/data/app/com.facebook.katana-1.apk\r\n" + " resourcePath=/data/app/com.facebook.katana-1.apk\r\n" + " nativeLibraryPath=/data/app-lib/com.facebook.katana-1\r\n" + " versionCode=1640376 targetSdk=14\r\n" + " versionName=8.0.0.0.23\r\n" + ""; Optional<PackageInfo> optionalInfo = ExopackageInstaller.parsePathAndPackageInfo("com.facebook.katana", lines); assertFalse(optionalInfo.isPresent()); } @Test public void testChunkArgs() { assertEquals(ImmutableList.of(), RealExopackageDevice.chunkArgs(ImmutableList.of(), 8)); assertEquals( ImmutableList.of(ImmutableList.of("abcd", "efg")), RealExopackageDevice.chunkArgs(ImmutableList.of("abcd", "efg"), 8)); assertEquals( ImmutableList.of(ImmutableList.of("abcd", "efg"), ImmutableList.of("hijkl")), RealExopackageDevice.chunkArgs(ImmutableList.of("abcd", "efg", "hijkl"), 8)); } @Test public void testFilterLibrariesForAbi() { Path libsDir = Paths.get("example"); ImmutableMultimap<String, Path> allLibs = ImmutableMultimap.of( Strings.repeat("a", 40), libsDir.resolve("libs/armeabi-v7a/libmy1.so"), Strings.repeat("b", 40), libsDir.resolve("libs/armeabi-v7a/libmy2.so"), Strings.repeat("c", 40), libsDir.resolve("libs/armeabi/libmy2.so"), Strings.repeat("d", 40), libsDir.resolve("libs/armeabi/libmy3.so"), Strings.repeat("e", 40), libsDir.resolve("libs/x86/libmy1.so")); assertEquals( ImmutableSet.of(Strings.repeat("a", 40), Strings.repeat("b", 40)), ExopackageInstaller.filterLibrariesForAbi( libsDir, allLibs, "armeabi-v7a", ImmutableSet.of()) .keySet()); assertEquals( ImmutableSet.of(Strings.repeat("d", 40)), ExopackageInstaller.filterLibrariesForAbi( libsDir, allLibs, "armeabi", ImmutableSet.of("libmy1.so", "libmy2.so")) .keySet()); } @Test public void testParseExopackageInfoMetadata() throws IOException { String illegalLine = "no_space_in_this_line_bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; thrown.expectMessage("Illegal line in metadata file: " + illegalLine); Path baseDir = Paths.get("basedir"); FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); filesystem.writeLinesToPath( ImmutableList.of( ".some_config", ".more_config with_spaces", "filename.jar aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "dir/anotherfile.jar bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), Paths.get("metadata.txt")); assertEquals( ImmutableMultimap.of( Strings.repeat("a", 40), Paths.get("basedir/filename.jar"), Strings.repeat("b", 40), Paths.get("basedir/dir/anotherfile.jar")), ExopackageInstaller.parseExopackageInfoMetadata( Paths.get("metadata.txt"), baseDir, filesystem)); filesystem.writeLinesToPath( ImmutableList.of("filename.jar aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", illegalLine), Paths.get("metadata.txt")); ExopackageInstaller.parseExopackageInfoMetadata(Paths.get("metadata.txt"), baseDir, filesystem); } @Test public void testNativeLibFilesPattern() { assertEquals("123abc", matchAndGetHash("native-123abc.so")); assertEquals(null, matchAndGetHash("native-123abcz.so")); assertEquals(null, matchAndGetHash("native-.so")); assertEquals(null, matchAndGetHash("secondary-123abc.so")); } private String matchAndGetHash(String filename) { Matcher m = NATIVE_LIB_PATTERN.matcher(filename); if (m.matches()) { return m.group(1); } return null; } }