diff options
Diffstat (limited to 'core/java')
8 files changed, 245 insertions, 18 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 2c04f8ff9548..8dc558ccf755 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -5872,6 +5872,16 @@ public class Activity extends ContextThemeWrapper } /** + * Temporary method on O-MR1 only. + * + * @hide + */ + @Override + public ComponentName getComponentNameForAutofill() { + return mComponent; + } + + /** * Retrieve a {@link SharedPreferences} object for accessing preferences * that are private to this activity. This simply calls the underlying * {@link #getSharedPreferences(String, int)} method by passing in this activity's diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java index 9383626360dc..bf715c35d9b7 100644 --- a/core/java/android/app/assist/AssistStructure.java +++ b/core/java/android/app/assist/AssistStructure.java @@ -2058,6 +2058,16 @@ public class AssistStructure implements Parcelable { return mActivityComponent; } + /** + * Called by Autofill server when app forged a different value. + * + * @hide + */ + public void setActivityComponent(ComponentName componentName) { + ensureData(); + mActivityComponent = componentName; + } + /** @hide */ public int getFlags() { return mFlags; diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java new file mode 100644 index 000000000000..9f5c877e7081 --- /dev/null +++ b/core/java/android/content/PermissionChecker.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2018 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; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AppOpsManager; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Process; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This class provides permission check APIs that verify both the + * permission and the associated app op for this permission if + * such is defined. + * <p> + * In the new permission model permissions with protection level + * dangerous are runtime permissions. For apps targeting {@link android.os.Build.VERSION_CODES#M} + * and above the user may not grant such permissions or revoke + * them at any time. For apps targeting API lower than {@link android.os.Build.VERSION_CODES#M} + * these permissions are always granted as such apps do not expect + * permission revocations and would crash. Therefore, when the + * user disables a permission for a legacy app in the UI the + * platform disables the APIs guarded by this permission making + * them a no-op which is doing nothing or returning an empty + * result or default error. + * </p> + * <p> + * It is important that when you perform an operation on behalf of + * another app you use these APIs to check for permissions as the + * app may be a legacy app that does not participate in the new + * permission model for which the user had disabled the "permission" + * which is achieved by disallowing the corresponding app op. + * </p> + * + * @hide + */ +public final class PermissionChecker { + /** Permission result: The permission is granted. */ + public static final int PERMISSION_GRANTED = PackageManager.PERMISSION_GRANTED; + + /** Permission result: The permission is denied. */ + public static final int PERMISSION_DENIED = PackageManager.PERMISSION_DENIED; + + /** Permission result: The permission is denied because the app op is not allowed. */ + public static final int PERMISSION_DENIED_APP_OP = PackageManager.PERMISSION_DENIED - 1; + + /** @hide */ + @IntDef({PERMISSION_GRANTED, + PERMISSION_DENIED, + PERMISSION_DENIED_APP_OP}) + @Retention(RetentionPolicy.SOURCE) + public @interface PermissionResult {} + + private PermissionChecker() { + /* do nothing */ + } + + /** + * Checks whether a given package in a UID and PID has a given permission + * and whether the app op that corresponds to this permission is allowed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @param pid The process id for which to check. + * @param uid The uid for which to check. + * @param packageName The package name for which to check. If null the + * the first package for the calling UID will be used. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + */ + @PermissionResult + public static int checkPermission(@NonNull Context context, @NonNull String permission, + int pid, int uid, @Nullable String packageName) { + if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { + return PERMISSION_DENIED; + } + + AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); + String op = appOpsManager.permissionToOp(permission); + if (op == null) { + return PERMISSION_GRANTED; + } + + if (packageName == null) { + String[] packageNames = context.getPackageManager().getPackagesForUid(uid); + if (packageNames == null || packageNames.length <= 0) { + return PERMISSION_DENIED; + } + packageName = packageNames[0]; + } + + if (appOpsManager.noteProxyOpNoThrow(op, packageName) + != AppOpsManager.MODE_ALLOWED) { + return PERMISSION_DENIED_APP_OP; + } + + return PERMISSION_GRANTED; + } + + /** + * Checks whether your app has a given permission and whether the app op + * that corresponds to this permission is allowed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + */ + @PermissionResult + public static int checkSelfPermission(@NonNull Context context, + @NonNull String permission) { + return checkPermission(context, permission, Process.myPid(), + Process.myUid(), context.getPackageName()); + } + + /** + * Checks whether the IPC you are handling has a given permission and whether + * the app op that corresponds to this permission is allowed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @param packageName The package name making the IPC. If null the + * the first package for the calling UID will be used. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + */ + @PermissionResult + public static int checkCallingPermission(@NonNull Context context, + @NonNull String permission, @Nullable String packageName) { + if (Binder.getCallingPid() == Process.myPid()) { + return PERMISSION_DENIED; + } + return checkPermission(context, permission, Binder.getCallingPid(), + Binder.getCallingUid(), packageName); + } + + /** + * Checks whether the IPC you are handling or your app has a given permission + * and whether the app op that corresponds to this permission is allowed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + */ + @PermissionResult + public static int checkCallingOrSelfPermission(@NonNull Context context, + @NonNull String permission) { + String packageName = (Binder.getCallingPid() == Process.myPid()) + ? context.getPackageName() : null; + return checkPermission(context, permission, Binder.getCallingPid(), + Binder.getCallingUid(), packageName); + } +} diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java index 674f809ef0f5..70dfef574ca5 100644 --- a/core/java/android/speech/RecognitionService.java +++ b/core/java/android/speech/RecognitionService.java @@ -20,7 +20,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.Service; import android.content.Intent; -import android.content.pm.PackageManager; +import android.content.PermissionChecker; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -174,8 +174,8 @@ public abstract class RecognitionService extends Service { */ private boolean checkPermissions(IRecognitionListener listener) { if (DBG) Log.d(TAG, "checkPermissions"); - if (RecognitionService.this.checkCallingOrSelfPermission(android.Manifest.permission. - RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) { + if (PermissionChecker.checkCallingOrSelfPermission(this, + android.Manifest.permission.RECORD_AUDIO) == PermissionChecker.PERMISSION_GRANTED) { return true; } try { diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 4fb2a99af575..fb9534b2e52e 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -24,6 +24,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; @@ -44,6 +45,7 @@ import android.view.View; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.util.Preconditions; import java.io.PrintWriter; import java.lang.annotation.Retention; @@ -384,13 +386,20 @@ public final class AutofillManager { * Runs the specified action on the UI thread. */ void runOnUiThread(Runnable action); + + /** + * Gets the complete component name of this client. + * + * <p>Temporary method on O-MR1 only. + */ + ComponentName getComponentNameForAutofill(); } /** * @hide */ public AutofillManager(Context context, IAutoFillManager service) { - mContext = context; + mContext = Preconditions.checkNotNull(context, "context cannot be null"); mService = service; } @@ -940,6 +949,10 @@ public final class AutofillManager { return mContext.getAutofillClient(); } + private ComponentName getComponentNameFromContext(AutofillClient client) { + return client == null ? null : client.getComponentNameForAutofill(); + } + /** @hide */ public void onAuthenticationResult(int authenticationId, Intent data) { if (!hasAutofillFeature()) { @@ -990,13 +1003,18 @@ public final class AutofillManager { return; } try { + final AutofillClient client = getClientLocked(); + final ComponentName componentName = getComponentNameFromContext(client); + if (componentName == null) { + Log.w(TAG, "startSessionLocked(): context is not activity: " + mContext); + return; + } mSessionId = mService.startSession(mContext.getActivityToken(), mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(), - mCallback != null, flags, mContext.getOpPackageName()); + mCallback != null, flags, componentName); if (mSessionId != NO_SESSION) { mState = STATE_ACTIVE; } - final AutofillClient client = getClientLocked(); if (client != null) { client.autofillCallbackResetableStateAvailable(); } @@ -1050,14 +1068,19 @@ public final class AutofillManager { try { if (restartIfNecessary) { + final AutofillClient client = getClientLocked(); + final ComponentName componentName = getComponentNameFromContext(client); + if (componentName == null) { + Log.w(TAG, "startSessionLocked(): context is not activity: " + mContext); + return; + } final int newId = mService.updateOrRestartSession(mContext.getActivityToken(), mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(), - mCallback != null, flags, mContext.getOpPackageName(), mSessionId, action); + mCallback != null, flags, componentName, mSessionId, action); if (newId != mSessionId) { if (sDebug) Log.d(TAG, "Session restarted: " + mSessionId + "=>" + newId); mSessionId = newId; mState = (mSessionId == NO_SESSION) ? STATE_UNKNOWN : STATE_ACTIVE; - final AutofillClient client = getClientLocked(); if (client != null) { client.autofillCallbackResetableStateAvailable(); } diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index 6bd9bec368c8..9329c4dcff6a 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -16,6 +16,7 @@ package android.view.autofill; +import android.content.ComponentName; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; @@ -34,14 +35,15 @@ interface IAutoFillManager { int addClient(in IAutoFillManagerClient client, int userId); int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags, - String packageName); + in ComponentName componentName); FillEventHistory getFillEventHistory(); boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback); void updateSession(int sessionId, in AutofillId id, in Rect bounds, in AutofillValue value, int action, int flags, int userId); int updateOrRestartSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId, - boolean hasCallback, int flags, String packageName, int sessionId, int action); + boolean hasCallback, int flags, in ComponentName componentName, int sessionId, + int action); void finishSession(int sessionId, int userId); void cancelSession(int sessionId, int userId); void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId); diff --git a/core/java/com/android/internal/app/procstats/SparseMappingTable.java b/core/java/com/android/internal/app/procstats/SparseMappingTable.java index 956ce99c0ad8..91b205479988 100644 --- a/core/java/com/android/internal/app/procstats/SparseMappingTable.java +++ b/core/java/com/android/internal/app/procstats/SparseMappingTable.java @@ -18,6 +18,7 @@ package com.android.internal.app.procstats; import android.os.Build; import android.os.Parcel; +import android.util.EventLog; import android.util.Slog; import libcore.util.EmptyArray; @@ -529,6 +530,12 @@ public class SparseMappingTable { readCompactedLongArray(in, array, size); mLongs.add(array); } + // Verify that last array's length is consistent with writeToParcel + if (N > 0 && mLongs.get(N - 1).length != mNextIndex) { + EventLog.writeEvent(0x534e4554, "73252178", -1, ""); + throw new IllegalStateException("Expected array of length " + mNextIndex + " but was " + + mLongs.get(N - 1).length); + } } /** diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java index d5b6def97426..df1ed7d392b2 100644 --- a/core/java/com/android/internal/widget/ViewPager.java +++ b/core/java/com/android/internal/widget/ViewPager.java @@ -31,6 +31,7 @@ import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.util.MathUtils; +import android.view.AbsSavedState; import android.view.FocusFinder; import android.view.Gravity; import android.view.KeyEvent; @@ -1198,15 +1199,11 @@ public class ViewPager extends ViewGroup { * state, in which case it should implement a subclass of this which * contains that state. */ - public static class SavedState extends BaseSavedState { + public static class SavedState extends AbsSavedState { int position; Parcelable adapterState; ClassLoader loader; - public SavedState(Parcel source) { - super(source); - } - public SavedState(Parcelable superState) { super(superState); } @@ -1225,10 +1222,15 @@ public class ViewPager extends ViewGroup { + " position=" + position + "}"; } - public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { + public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() { + @Override + public SavedState createFromParcel(Parcel in, ClassLoader loader) { + return new SavedState(in, loader); + } + @Override public SavedState createFromParcel(Parcel in) { - return new SavedState(in); + return new SavedState(in, null); } @Override public SavedState[] newArray(int size) { @@ -1237,7 +1239,7 @@ public class ViewPager extends ViewGroup { }; SavedState(Parcel in, ClassLoader loader) { - super(in); + super(in, loader); if (loader == null) { loader = getClass().getClassLoader(); } |