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