blob: d5898b7f57a1a5e1f8c2e64f72679502b735267f [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.result;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.pm.PackageManager;
import android.os.Build;
/**
* Used as a method parameter which is then transformed into a {@link ParseResult}. This is
* generalized as it doesn't matter what type this input is for. It's simply to hide the
* methods of {@link ParseResult}.
*
* @hide
*/
public interface ParseInput {
/**
* Errors encountered during parsing may rely on the targetSDK version of the application to
* determine whether or not to fail. These are passed into {@link #deferError(String, long)}
* when encountered, and the implementation will handle how to defer the errors until the
* targetSdkVersion is known and sent to {@link #enableDeferredError(String, int)}.
*
* All of these must be marked {@link ChangeId}, as that is the mechanism used to check if the
* error must be propagated. This framework also allows developers to pre-disable specific
* checks if they wish to target a newer SDK version in a development environment without
* having to migrate their entire app to validate on a newer platform.
*/
final class DeferredError {
/**
* Missing an "application" or "instrumentation" tag.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
public static final long MISSING_APP_TAG = 150776642;
/**
* An intent filter's actor or category is an empty string. A bug in the platform before R
* allowed this to pass through without an error. This does not include cases when the
* attribute is null/missing, as that has always been a failure.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
public static final long EMPTY_INTENT_ACTION_CATEGORY = 151163173;
/**
* The {@code resources.arsc} of one of the APKs being installed is compressed or not
* aligned on a 4-byte boundary. Resource tables that cannot be memory mapped exert excess
* memory pressure on the system and drastically slow down construction of
* {@link android.content.res.Resources} objects.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
public static final long RESOURCES_ARSC_COMPRESSED = 132742131;
}
<ResultType> ParseResult<ResultType> success(ResultType result);
/**
* Used for errors gated by {@link DeferredError}. Will return an error result if the
* targetSdkVersion is already known and this must be returned as a real error. The result
* contains null and should not be unwrapped.
*
* @see #error(String)
*/
ParseResult<?> deferError(@NonNull String parseError, long deferredError);
/**
* Called after targetSdkVersion is known. Returns an error result if a previously deferred
* error was registered. The result contains null and should not be unwrapped.
*/
ParseResult<?> enableDeferredError(String packageName, int targetSdkVersion);
/**
* This will assign errorCode to {@link PackageManager#INSTALL_PARSE_FAILED_SKIPPED, used for
* packages which should be ignored by the caller.
*
* @see #error(int, String, Exception)
*/
<ResultType> ParseResult<ResultType> skip(@NonNull String parseError);
/** @see #error(int, String, Exception) */
<ResultType> ParseResult<ResultType> error(int parseError);
/**
* This will assign errorCode to {@link PackageManager#INSTALL_PARSE_FAILED_MANIFEST_MALFORMED}.
* @see #error(int, String, Exception)
*/
<ResultType> ParseResult<ResultType> error(@NonNull String parseError);
/** @see #error(int, String, Exception) */
<ResultType> ParseResult<ResultType> error(int parseError, @Nullable String errorMessage);
/**
* Marks this as an error result. When this method is called, the return value <b>must</b>
* be returned to the exit of the parent method that took in this {@link ParseInput} as a
* parameter.
*
* The calling site of that method is then expected to check the result for error, and
* continue to bubble up if it is an error.
*
* If the result {@link ParseResult#isSuccess()}, then it can be used as-is, as
* overlapping/consecutive successes are allowed.
*/
<ResultType> ParseResult<ResultType> error(int parseError, @Nullable String errorMessage,
@Nullable Exception exception);
/**
* Moves the error in {@param result} to this input's type. In practice this does nothing
* but cast the type of the {@link ParseResult} for type safety, since the parameter
* and the receiver should be the same object.
*/
<ResultType> ParseResult<ResultType> error(ParseResult<?> result);
/**
* Implemented instead of a direct reference to
* {@link com.android.internal.compat.IPlatformCompat}, allowing caching and testing logic to
* be separated out.
*/
interface Callback {
/**
* @return true if the changeId should be enabled
*/
boolean isChangeEnabled(long changeId, @NonNull String packageName, int targetSdkVersion);
}
}