1// Copyright 2018 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package dexpreopt 16 17import ( 18 "android/soong/android" 19 "reflect" 20 "strings" 21 "testing" 22) 23 24func testModuleConfig(ctx android.PathContext) ModuleConfig { 25 return ModuleConfig{ 26 Name: "test", 27 DexLocation: "/system/app/test/test.apk", 28 BuildPath: android.PathForOutput(ctx, "test/test.apk"), 29 DexPath: android.PathForOutput(ctx, "test/dex/test.jar"), 30 UncompressedDex: false, 31 HasApkLibraries: false, 32 PreoptFlags: nil, 33 ProfileClassListing: android.OptionalPath{}, 34 ProfileIsTextListing: false, 35 EnforceUsesLibraries: false, 36 OptionalUsesLibraries: nil, 37 UsesLibraries: nil, 38 LibraryPaths: nil, 39 Archs: []android.ArchType{android.Arm}, 40 DexPreoptImages: android.Paths{android.PathForTesting("system/framework/arm/boot.art")}, 41 PreoptBootClassPathDexFiles: nil, 42 PreoptBootClassPathDexLocations: nil, 43 PreoptExtractedApk: false, 44 NoCreateAppImage: false, 45 ForceCreateAppImage: false, 46 PresignedPrebuilt: false, 47 NoStripping: false, 48 StripInputPath: android.PathForOutput(ctx, "unstripped/test.apk"), 49 StripOutputPath: android.PathForOutput(ctx, "stripped/test.apk"), 50 } 51} 52 53func TestDexPreopt(t *testing.T) { 54 ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) 55 global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) 56 57 rule, err := GenerateDexpreoptRule(ctx, global, module) 58 if err != nil { 59 t.Fatal(err) 60 } 61 62 wantInstalls := android.RuleBuilderInstalls{ 63 {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, 64 {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, 65 } 66 67 if rule.Installs().String() != wantInstalls.String() { 68 t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) 69 } 70} 71 72func TestDexPreoptStrip(t *testing.T) { 73 // Test that we panic if we strip in a configuration where stripping is not allowed. 74 ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) 75 global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) 76 77 global.NeverAllowStripping = true 78 module.NoStripping = false 79 80 _, err := GenerateStripRule(global, module) 81 if err == nil { 82 t.Errorf("Expected an error when calling GenerateStripRule on a stripped module") 83 } 84} 85 86func TestDexPreoptSystemOther(t *testing.T) { 87 ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) 88 global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) 89 90 global.HasSystemOther = true 91 global.PatternsOnSystemOther = []string{"app/%"} 92 93 rule, err := GenerateDexpreoptRule(ctx, global, module) 94 if err != nil { 95 t.Fatal(err) 96 } 97 98 wantInstalls := android.RuleBuilderInstalls{ 99 {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system_other/app/test/oat/arm/test.odex"}, 100 {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system_other/app/test/oat/arm/test.vdex"}, 101 } 102 103 if rule.Installs().String() != wantInstalls.String() { 104 t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) 105 } 106} 107 108func TestDexPreoptProfile(t *testing.T) { 109 ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) 110 global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) 111 112 module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile")) 113 114 rule, err := GenerateDexpreoptRule(ctx, global, module) 115 if err != nil { 116 t.Fatal(err) 117 } 118 119 wantInstalls := android.RuleBuilderInstalls{ 120 {android.PathForOutput(ctx, "test/profile.prof"), "/system/app/test/test.apk.prof"}, 121 {android.PathForOutput(ctx, "test/oat/arm/package.art"), "/system/app/test/oat/arm/test.art"}, 122 {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, 123 {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, 124 } 125 126 if rule.Installs().String() != wantInstalls.String() { 127 t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) 128 } 129} 130 131func TestStripDex(t *testing.T) { 132 tests := []struct { 133 name string 134 setup func(global *GlobalConfig, module *ModuleConfig) 135 strip bool 136 }{ 137 { 138 name: "default strip", 139 setup: func(global *GlobalConfig, module *ModuleConfig) {}, 140 strip: true, 141 }, 142 { 143 name: "global no stripping", 144 setup: func(global *GlobalConfig, module *ModuleConfig) { global.DefaultNoStripping = true }, 145 strip: false, 146 }, 147 { 148 name: "module no stripping", 149 setup: func(global *GlobalConfig, module *ModuleConfig) { module.NoStripping = true }, 150 strip: false, 151 }, 152 } 153 154 for _, test := range tests { 155 t.Run(test.name, func(t *testing.T) { 156 157 ctx := android.PathContextForTesting(android.TestConfig("out", nil), nil) 158 global, module := GlobalConfigForTests(ctx), testModuleConfig(ctx) 159 160 test.setup(&global, &module) 161 162 rule, err := GenerateStripRule(global, module) 163 if err != nil { 164 t.Fatal(err) 165 } 166 167 if test.strip { 168 want := `zip2zip -i out/unstripped/test.apk -o out/stripped/test.apk -x "classes*.dex"` 169 if len(rule.Commands()) < 1 || !strings.Contains(rule.Commands()[0], want) { 170 t.Errorf("\nwant commands[0] to have:\n %v\ngot:\n %v", want, rule.Commands()[0]) 171 } 172 } else { 173 wantCommands := []string{ 174 "cp -f out/unstripped/test.apk out/stripped/test.apk", 175 } 176 if !reflect.DeepEqual(rule.Commands(), wantCommands) { 177 t.Errorf("\nwant commands:\n %v\ngot:\n %v", wantCommands, rule.Commands()) 178 } 179 } 180 }) 181 } 182} 183