1 /* 2 * Copyright (C) 2022 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 17 package com.android.server.pm.pkg.component; 18 19 import android.annotation.NonNull; 20 import android.content.pm.ApplicationInfo; 21 import android.content.pm.parsing.result.ParseInput; 22 import android.content.pm.parsing.result.ParseResult; 23 import android.content.res.Resources; 24 import android.content.res.TypedArray; 25 import android.content.res.XmlResourceParser; 26 import android.util.ArrayMap; 27 import android.util.ArraySet; 28 29 import com.android.internal.R; 30 import com.android.internal.util.CollectionUtils; 31 import com.android.internal.util.XmlUtils; 32 import com.android.server.pm.pkg.parsing.ParsingPackage; 33 import com.android.server.pm.pkg.parsing.ParsingUtils; 34 35 import org.xmlpull.v1.XmlPullParser; 36 import org.xmlpull.v1.XmlPullParserException; 37 38 import java.io.IOException; 39 import java.util.Set; 40 41 /** @hide */ 42 public class ParsedProcessUtils { 43 44 @NonNull parseDenyPermission(Set<String> perms, Resources res, XmlResourceParser parser, ParseInput input)45 private static ParseResult<Set<String>> parseDenyPermission(Set<String> perms, 46 Resources res, XmlResourceParser parser, ParseInput input) 47 throws IOException, XmlPullParserException { 48 TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestDenyPermission); 49 try { 50 String perm = sa.getNonConfigurationString( 51 R.styleable.AndroidManifestDenyPermission_name, 0); 52 if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) { 53 perms = CollectionUtils.add(perms, perm); 54 } 55 } finally { 56 sa.recycle(); 57 } 58 XmlUtils.skipCurrentTag(parser); 59 return input.success(perms); 60 } 61 62 @NonNull parseAllowPermission(Set<String> perms, Resources res, XmlResourceParser parser, ParseInput input)63 private static ParseResult<Set<String>> parseAllowPermission(Set<String> perms, Resources res, 64 XmlResourceParser parser, ParseInput input) 65 throws IOException, XmlPullParserException { 66 TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAllowPermission); 67 try { 68 String perm = sa.getNonConfigurationString( 69 R.styleable.AndroidManifestAllowPermission_name, 0); 70 if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) { 71 perms = CollectionUtils.remove(perms, perm); 72 } 73 } finally { 74 sa.recycle(); 75 } 76 XmlUtils.skipCurrentTag(parser); 77 return input.success(perms); 78 } 79 80 @NonNull parseProcess(Set<String> perms, String[] separateProcesses, ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, ParseInput input)81 private static ParseResult<ParsedProcess> parseProcess(Set<String> perms, String[] separateProcesses, 82 ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, 83 ParseInput input) throws IOException, XmlPullParserException { 84 ParsedProcessImpl proc = new ParsedProcessImpl(); 85 TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess); 86 try { 87 if (perms != null) { 88 proc.setDeniedPermissions(new ArraySet<>(perms)); 89 } 90 91 String processName = sa.getNonConfigurationString( 92 R.styleable.AndroidManifestProcess_process, 0); 93 ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName( 94 pkg.getPackageName(), pkg.getPackageName(), processName, flags, separateProcesses, 95 input); 96 if (processNameResult.isError()) { 97 return input.error(processNameResult); 98 } 99 100 String packageName = pkg.getPackageName(); 101 String className = ParsingUtils.buildClassName(packageName, 102 sa.getNonConfigurationString(R.styleable.AndroidManifestProcess_name, 0)); 103 104 proc.setName(processNameResult.getResult()); 105 proc.putAppClassNameForPackage(packageName, className); 106 proc.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestProcess_gwpAsanMode, -1)); 107 proc.setMemtagMode(sa.getInt(R.styleable.AndroidManifestProcess_memtagMode, -1)); 108 if (sa.hasValue(R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized)) { 109 final boolean v = sa.getBoolean( 110 R.styleable.AndroidManifestProcess_nativeHeapZeroInitialized, false); 111 proc.setNativeHeapZeroInitialized( 112 v ? ApplicationInfo.ZEROINIT_ENABLED : ApplicationInfo.ZEROINIT_DISABLED); 113 } 114 } finally { 115 sa.recycle(); 116 } 117 118 int type; 119 final int innerDepth = parser.getDepth(); 120 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 121 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 122 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 123 continue; 124 } 125 126 ParseResult<?> result; 127 128 String tagName = parser.getName(); 129 switch (tagName) { 130 case "deny-permission": 131 ParseResult<Set<String>> denyResult = parseDenyPermission( 132 proc.getDeniedPermissions(), res, parser, input); 133 result = denyResult; 134 if (denyResult.isSuccess()) { 135 proc.setDeniedPermissions(denyResult.getResult()); 136 } 137 break; 138 case "allow-permission": 139 ParseResult<Set<String>> allowResult = parseAllowPermission( 140 proc.getDeniedPermissions(), res, parser, input); 141 result = allowResult; 142 if (allowResult.isSuccess()) { 143 proc.setDeniedPermissions(allowResult.getResult()); 144 } 145 break; 146 default: 147 result = ParsingUtils.unknownTag("<process>", pkg, parser, input); 148 break; 149 } 150 151 if (result.isError()) { 152 return input.error(result); 153 } 154 } 155 156 return input.success(proc); 157 } 158 159 @NonNull parseProcesses( String[] separateProcesses, ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, ParseInput input)160 public static ParseResult<ArrayMap<String, ParsedProcess>> parseProcesses( 161 String[] separateProcesses, ParsingPackage pkg, Resources res, 162 XmlResourceParser parser, int flags, ParseInput input) 163 throws IOException, XmlPullParserException { 164 Set<String> deniedPerms = null; 165 ArrayMap<String, ParsedProcess> processes = new ArrayMap<>(); 166 167 int type; 168 final int innerDepth = parser.getDepth(); 169 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 170 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { 171 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 172 continue; 173 } 174 175 ParseResult<?> result; 176 177 String tagName = parser.getName(); 178 switch (tagName) { 179 case "deny-permission": 180 ParseResult<Set<String>> denyResult = parseDenyPermission(deniedPerms, res, 181 parser, input); 182 result = denyResult; 183 if (denyResult.isSuccess()) { 184 deniedPerms = denyResult.getResult(); 185 } 186 break; 187 case "allow-permission": 188 ParseResult<Set<String>> allowResult = parseAllowPermission(deniedPerms, res, 189 parser, input); 190 result = allowResult; 191 if (allowResult.isSuccess()) { 192 deniedPerms = allowResult.getResult(); 193 } 194 break; 195 case "process": 196 ParseResult<ParsedProcess> processResult = parseProcess(deniedPerms, 197 separateProcesses, pkg, res, parser, flags, input); 198 result = processResult; 199 if (processResult.isSuccess()) { 200 ParsedProcess process = processResult.getResult(); 201 if (processes.put(process.getName(), process) != null) { 202 result = input.error( 203 "<process> specified existing name '" + process.getName() + "'"); 204 } 205 } 206 break; 207 default: 208 result = ParsingUtils.unknownTag("<processes>", pkg, parser, input); 209 break; 210 } 211 212 if (result.isError()) { 213 return input.error(result); 214 } 215 216 } 217 218 return input.success(processes); 219 } 220 } 221