1 /* 2 * Copyright (C) 2012 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 package com.android.tradefed.util; 17 18 import com.android.tradefed.log.LogUtil.CLog; 19 20 import java.io.File; 21 import java.util.ArrayList; 22 import java.util.List; 23 import java.util.regex.Matcher; 24 import java.util.regex.Pattern; 25 26 /** 27 * Class that extracts info from apk by parsing output of 'aapt dump badging'. 28 * <p/> 29 * aapt must be on PATH 30 */ 31 public class AaptParser { 32 private static final Pattern PKG_PATTERN = Pattern.compile( 33 "^package:\\s+name='(.*?)'\\s+versionCode='(\\d*)'\\s+versionName='(.*?)'.*$", 34 Pattern.MULTILINE); 35 private static final Pattern LABEL_PATTERN = Pattern.compile( 36 "^application-label:'(.+?)'.*$", 37 Pattern.MULTILINE); 38 private static final Pattern SDK_PATTERN = Pattern.compile( 39 "^sdkVersion:'(\\d+)'", Pattern.MULTILINE); 40 /** Patterns for native code are not always present, so the list may stay empty. */ 41 private static final Pattern NATIVE_CODE_PATTERN = 42 Pattern.compile("native-code: '(.*?)'( '.*?')*"); 43 44 private static final Pattern ALT_NATIVE_CODE_PATTERN = 45 Pattern.compile("alt-native-code: '(.*)'"); 46 private static final int AAPT_TIMEOUT_MS = 60000; 47 private static final int INVALID_SDK = -1; 48 49 private String mPackageName; 50 private String mVersionCode; 51 private String mVersionName; 52 private List<String> mNativeCode = new ArrayList<>(); 53 private String mLabel; 54 private int mSdkVersion = INVALID_SDK; 55 56 // @VisibleForTesting 57 AaptParser() { 58 } 59 60 boolean parse(String aaptOut) { 61 //CLog.e(aaptOut); 62 Matcher m = PKG_PATTERN.matcher(aaptOut); 63 if (m.find()) { 64 mPackageName = m.group(1); 65 mLabel = mPackageName; 66 mVersionCode = m.group(2); 67 mVersionName = m.group(3); 68 m = LABEL_PATTERN.matcher(aaptOut); 69 if (m.find()) { 70 mLabel = m.group(1); 71 } 72 m = SDK_PATTERN.matcher(aaptOut); 73 if (m.find()) { 74 mSdkVersion = Integer.parseInt(m.group(1)); 75 } 76 m = NATIVE_CODE_PATTERN.matcher(aaptOut); 77 if (m.find()) { 78 for (int i = 1; i <= m.groupCount(); i++) { 79 if (m.group(i) != null) { 80 mNativeCode.add(m.group(i).replace("'", "").trim()); 81 } 82 } 83 } 84 m = ALT_NATIVE_CODE_PATTERN.matcher(aaptOut); 85 if (m.find()) { 86 for (int i = 1; i <= m.groupCount(); i++) { 87 if (m.group(i) != null) { 88 mNativeCode.add(m.group(i).replace("'", "")); 89 } 90 } 91 } 92 return true; 93 } 94 CLog.e("Failed to parse package and version info from 'aapt dump badging'. stdout: '%s'", 95 aaptOut); 96 return false; 97 } 98 99 /** 100 * Parse info from the apk. 101 * 102 * @param apkFile the apk file 103 * @return the {@link AaptParser} or <code>null</code> if failed to extract the information 104 */ 105 public static AaptParser parse(File apkFile) { 106 CommandResult result = RunUtil.getDefault().runTimedCmd(AAPT_TIMEOUT_MS, 107 "aapt", "dump", "badging", apkFile.getAbsolutePath()); 108 109 String stderr = result.getStderr(); 110 if (stderr != null && stderr.length() > 0) { 111 CLog.e("aapt dump badging stderr: %s", stderr); 112 } 113 114 if (result.getStatus() == CommandStatus.SUCCESS) { 115 AaptParser p = new AaptParser(); 116 if (p.parse(result.getStdout())) 117 return p; 118 return null; 119 } 120 CLog.e("Failed to run aapt on %s", apkFile.getAbsoluteFile()); 121 return null; 122 } 123 124 public String getPackageName() { 125 return mPackageName; 126 } 127 128 public String getVersionCode() { 129 return mVersionCode; 130 } 131 132 public String getVersionName() { 133 return mVersionName; 134 } 135 136 public List<String> getNativeCode() { 137 return mNativeCode; 138 } 139 140 public String getLabel() { 141 return mLabel; 142 } 143 144 public int getSdkVersion() { 145 return mSdkVersion; 146 } 147 } 148