| // 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. |
| |
| // Package apk provides methods to get information (e.g. manifests, ABIs) |
| // from APKs, as well as taking an APK and making it debuggable, for testing |
| // purposes. |
| package apk |
| |
| import ( |
| "archive/zip" |
| "bytes" |
| "io/ioutil" |
| "strings" |
| |
| "android.googlesource.com/platform/tools/gpu/client/android/binaryxml" |
| "android.googlesource.com/platform/tools/gpu/client/android/manifest" |
| "android.googlesource.com/platform/tools/gpu/framework/device" |
| "android.googlesource.com/platform/tools/gpu/framework/log" |
| ) |
| |
| const mainfestPath = "AndroidManifest.xml" |
| |
| // Read parses the APK file, returning its contents. |
| func Read(ctx log.Context, apkData []byte) ([]*zip.File, error) { |
| apkZip, err := zip.NewReader(bytes.NewReader(apkData), int64(len(apkData))) |
| if err != nil { |
| return nil, ctx.AsError("File is not an APK.") |
| } |
| return apkZip.File, nil |
| } |
| |
| func GetManifestXML(ctx log.Context, files []*zip.File) (string, error) { |
| manifestZipFile := findManifest(files) |
| if manifestZipFile == nil { |
| return "", ctx.AsError("Couldn't find APK's manifest file.") |
| } |
| |
| manifestFile, err := manifestZipFile.Open() |
| if err != nil { |
| return "", ctx.WrapError(err, "Couldn't open APK's manifest") |
| } |
| defer manifestFile.Close() |
| |
| manifestData, _ := ioutil.ReadAll(manifestFile) |
| |
| return binaryxml.Decode(ctx, manifestData) |
| } |
| |
| func GetManifest(ctx log.Context, files []*zip.File) (manifest.Manifest, error) { |
| manifestXML, err := GetManifestXML(ctx, files) |
| if err != nil { |
| return manifest.Manifest{}, err |
| } |
| return manifest.Parse(ctx, manifestXML) |
| } |
| |
| func findManifest(files []*zip.File) *zip.File { |
| for _, file := range files { |
| if file.Name == mainfestPath { |
| return file |
| } |
| } |
| return nil |
| } |
| |
| func GatherABIs(files []*zip.File) []*device.ABI { |
| abis := []*device.ABI{} |
| seen := map[string]struct{}{} |
| for _, f := range files { |
| parts := strings.Split(f.Name, "/") |
| if len(parts) >= 2 && parts[0] == "lib" { |
| abiName := parts[1] |
| if _, existing := seen[abiName]; !existing { |
| abi := device.ABIByName(abiName) |
| abis = append(abis, &abi) |
| seen[abiName] = struct{}{} |
| } |
| } |
| } |
| return abis |
| } |