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.internal.pm.pkg.component; 18 19 import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET; 20 21 import android.annotation.FlaggedApi; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.content.IntentFilter; 25 import android.content.pm.parsing.result.ParseInput; 26 import android.content.pm.parsing.result.ParseResult; 27 import android.content.res.Configuration; 28 import android.content.res.Resources; 29 import android.content.res.TypedArray; 30 import android.content.res.XmlResourceParser; 31 import android.os.Build; 32 import android.util.Slog; 33 34 import com.android.internal.annotations.VisibleForTesting; 35 import com.android.internal.pm.pkg.parsing.ParsingPackage; 36 import com.android.internal.pm.pkg.parsing.ParsingUtils; 37 38 import org.xmlpull.v1.XmlPullParserException; 39 40 import java.io.IOException; 41 42 /** @hide */ 43 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 44 public class ParsedMainComponentUtils { 45 46 private static final String TAG = ParsingUtils.TAG; 47 48 @NonNull 49 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) parseMainComponent( Component component, String tag, String[] separateProcesses, ParsingPackage pkg, TypedArray array, int flags, boolean useRoundIcon, @Nullable String defaultSplitName, @NonNull ParseInput input, int bannerAttr, int descriptionAttr, int directBootAwareAttr, int enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr, int processAttr, int roundIconAttr, int splitNameAttr, int attributionTagsAttr, int intentMatchingFlagsAttr)50 static <Component extends ParsedMainComponentImpl> ParseResult<Component> parseMainComponent( 51 Component component, String tag, String[] separateProcesses, ParsingPackage pkg, 52 TypedArray array, int flags, boolean useRoundIcon, @Nullable String defaultSplitName, 53 @NonNull ParseInput input, int bannerAttr, int descriptionAttr, int directBootAwareAttr, 54 int enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr, 55 int processAttr, int roundIconAttr, int splitNameAttr, int attributionTagsAttr, 56 int intentMatchingFlagsAttr) { 57 ParseResult<Component> result = ParsedComponentUtils.parseComponent(component, tag, pkg, 58 array, useRoundIcon, input, bannerAttr, descriptionAttr, iconAttr, labelAttr, 59 logoAttr, nameAttr, roundIconAttr); 60 if (result.isError()) { 61 return result; 62 } 63 64 if (directBootAwareAttr != NOT_SET) { 65 component.setDirectBootAware(array.getBoolean(directBootAwareAttr, false)); 66 if (component.isDirectBootAware()) { 67 pkg.setPartiallyDirectBootAware(true); 68 } 69 } 70 71 if (enabledAttr != NOT_SET) { 72 component.setEnabled(array.getBoolean(enabledAttr, true)); 73 } 74 75 if (processAttr != NOT_SET) { 76 CharSequence processName; 77 if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) { 78 processName = array.getNonConfigurationString(processAttr, 79 Configuration.NATIVE_CONFIG_VERSION); 80 } else { 81 // Some older apps have been seen to use a resource reference 82 // here that on older builds was ignored (with a warning). We 83 // need to continue to do this for them so they don't break. 84 processName = array.getNonResourceString(processAttr); 85 } 86 87 // Backwards-compat, ignore error 88 ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName( 89 pkg.getPackageName(), pkg.getProcessName(), processName, flags, 90 separateProcesses, input); 91 if (processNameResult.isError()) { 92 return input.error(processNameResult); 93 } 94 95 component.setProcessName(processNameResult.getResult()); 96 } 97 98 if (splitNameAttr != NOT_SET) { 99 component.setSplitName(array.getNonConfigurationString(splitNameAttr, 0)); 100 } 101 102 if (defaultSplitName != null && component.getSplitName() == null) { 103 component.setSplitName(defaultSplitName); 104 } 105 106 if (attributionTagsAttr != NOT_SET) { 107 final String attributionTags = array.getNonConfigurationString(attributionTagsAttr, 0); 108 if (attributionTags != null) { 109 component.setAttributionTags(attributionTags.split("\\|")); 110 } 111 } 112 113 if (android.security.Flags.enableIntentMatchingFlags()) { 114 int resolvedFlags = resolveIntentMatchingFlags( 115 pkg.getIntentMatchingFlags(), array.getInt(intentMatchingFlagsAttr, 0)); 116 component.setIntentMatchingFlags(resolvedFlags); 117 } 118 119 return input.success(component); 120 } 121 parseIntentFilter( ParsedMainComponent mainComponent, ParsingPackage pkg, Resources resources, XmlResourceParser parser, boolean visibleToEphemeral, boolean allowGlobs, boolean allowAutoVerify, boolean allowImplicitEphemeralVisibility, boolean failOnNoActions, ParseInput input)122 static ParseResult<ParsedIntentInfoImpl> parseIntentFilter( 123 ParsedMainComponent mainComponent, 124 ParsingPackage pkg, Resources resources, XmlResourceParser parser, 125 boolean visibleToEphemeral, boolean allowGlobs, boolean allowAutoVerify, 126 boolean allowImplicitEphemeralVisibility, boolean failOnNoActions, 127 ParseInput input) throws IOException, XmlPullParserException { 128 ParseResult<ParsedIntentInfoImpl> intentResult = ParsedIntentInfoUtils.parseIntentInfo( 129 mainComponent.getName(), pkg, resources, parser, allowGlobs, 130 allowAutoVerify, input); 131 if (intentResult.isError()) { 132 return input.error(intentResult); 133 } 134 135 ParsedIntentInfo intent = intentResult.getResult(); 136 IntentFilter intentFilter = intent.getIntentFilter(); 137 int actionCount = intentFilter.countActions(); 138 if (actionCount == 0 && failOnNoActions) { 139 Slog.w(TAG, "No actions in " + parser.getName() + " at " + pkg.getBaseApkPath() + " " 140 + parser.getPositionDescription()); 141 // Backward-compat, do not actually fail 142 return input.success(null); 143 } 144 145 int intentVisibility; 146 if (visibleToEphemeral) { 147 intentVisibility = IntentFilter.VISIBILITY_EXPLICIT; 148 } else if (allowImplicitEphemeralVisibility 149 && ComponentParseUtils.isImplicitlyExposedIntent(intent)){ 150 intentVisibility = IntentFilter.VISIBILITY_IMPLICIT; 151 } else { 152 intentVisibility = IntentFilter.VISIBILITY_NONE; 153 } 154 intentFilter.setVisibilityToInstantApp(intentVisibility); 155 156 return input.success(intentResult.getResult()); 157 } 158 159 /** 160 * Resolves intent matching flags from the application and a component, prioritizing the 161 * component's flags. 162 * 163 * @param applicationFlags The flag value from the "application" tag. 164 * @param componentFlags The flag value from the "component" tags. 165 * @return The resolved intent matching flags. 166 */ 167 @FlaggedApi(android.security.Flags.FLAG_ENABLE_INTENT_MATCHING_FLAGS) 168 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) resolveIntentMatchingFlags(int applicationFlags, int componentFlags)169 public static int resolveIntentMatchingFlags(int applicationFlags, int componentFlags) { 170 if (componentFlags == 0) { 171 return applicationFlags; 172 } else { 173 return componentFlags; 174 } 175 } 176 } 177