blob: 8a8a066839e366451c3403deab4c8bff72e49e53 [file] [log] [blame]
/*
* Copyright (C) 2020 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 android.content.pm.parsing.component;
import static android.content.pm.parsing.component.ComponentParseUtils.flag;
import android.annotation.NonNull;
import android.content.pm.ActivityInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.parsing.ParsingPackage;
import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.Objects;
/** @hide */
public class ParsedServiceUtils {
private static final String TAG = ParsingPackageUtils.TAG;
@NonNull
public static ParseResult<ParsedService> parseService(String[] separateProcesses,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
boolean useRoundIcon, ParseInput input)
throws XmlPullParserException, IOException {
boolean visibleToEphemeral;
boolean setExported;
final String packageName = pkg.getPackageName();
final ParsedService service = new ParsedService();
String tag = parser.getName();
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestService);
try {
ParseResult<ParsedService> result = ParsedMainComponentUtils.parseMainComponent(
service, tag, separateProcesses, pkg, sa, flags, useRoundIcon, input,
R.styleable.AndroidManifestService_banner,
R.styleable.AndroidManifestService_description,
R.styleable.AndroidManifestService_directBootAware,
R.styleable.AndroidManifestService_enabled,
R.styleable.AndroidManifestService_icon,
R.styleable.AndroidManifestService_label,
R.styleable.AndroidManifestService_logo,
R.styleable.AndroidManifestService_name,
R.styleable.AndroidManifestService_process,
R.styleable.AndroidManifestService_roundIcon,
R.styleable.AndroidManifestService_splitName
);
if (result.isError()) {
return result;
}
setExported = sa.hasValue(R.styleable.AndroidManifestService_exported);
if (setExported) {
service.exported = sa.getBoolean(R.styleable.AndroidManifestService_exported,
false);
}
String permission = sa.getNonConfigurationString(
R.styleable.AndroidManifestService_permission, 0);
service.setPermission(permission != null ? permission : pkg.getPermission());
service.foregroundServiceType = sa.getInt(
R.styleable.AndroidManifestService_foregroundServiceType,
ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
service.flags |= flag(ServiceInfo.FLAG_STOP_WITH_TASK,
R.styleable.AndroidManifestService_stopWithTask, sa)
| flag(ServiceInfo.FLAG_ISOLATED_PROCESS,
R.styleable.AndroidManifestService_isolatedProcess, sa)
| flag(ServiceInfo.FLAG_EXTERNAL_SERVICE,
R.styleable.AndroidManifestService_externalService, sa)
| flag(ServiceInfo.FLAG_USE_APP_ZYGOTE,
R.styleable.AndroidManifestService_useAppZygote, sa)
| flag(ServiceInfo.FLAG_SINGLE_USER,
R.styleable.AndroidManifestService_singleUser, sa);
visibleToEphemeral = sa.getBoolean(
R.styleable.AndroidManifestService_visibleToInstantApps, false);
if (visibleToEphemeral) {
service.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
pkg.setVisibleToInstantApps(true);
}
} finally {
sa.recycle();
}
if (pkg.isCantSaveState()) {
// A heavy-weight application can not have services in its main process
// We can do direct compare because we intern all strings.
if (Objects.equals(service.getProcessName(), packageName)) {
return input.error("Heavy-weight applications can not have services "
+ "in main process");
}
}
final int depth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > depth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
final ParseResult parseResult;
switch (parser.getName()) {
case "intent-filter":
ParseResult<ParsedIntentInfo> intentResult = ParsedMainComponentUtils
.parseIntentFilter(service, pkg, res, parser, visibleToEphemeral,
true /*allowGlobs*/, false /*allowAutoVerify*/,
false /*allowImplicitEphemeralVisibility*/,
false /*failOnNoActions*/, input);
parseResult = intentResult;
if (intentResult.isSuccess()) {
ParsedIntentInfo intent = intentResult.getResult();
service.order = Math.max(intent.getOrder(), service.order);
service.addIntent(intent);
}
break;
case "meta-data":
parseResult = ParsedComponentUtils.addMetaData(service, pkg, res, parser, input);
break;
default:
parseResult = ParsingUtils.unknownTag(tag, pkg, parser, input);
break;
}
if (parseResult.isError()) {
return input.error(parseResult);
}
}
if (!setExported) {
service.exported = service.getIntents().size() > 0;
}
return input.success(service);
}
}