Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4703a5a6 authored by Arc Wang's avatar Arc Wang
Browse files

Allow 2-pane deep link to access unexported Activity



If an Activity is not exported, the Activity still can be
launched by components of the same application, applications
with the same user ID, or privileged system components.

Bug: 261678674
Bug: 250589026
Change-Id: I2c70271ac50c7bb5f0bb8275d079ed553f0e50b0
Merged-In: I662df6cb287361b135e2c596abe946ddeb03bda4
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 76b6947b 04989073
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
@@ -27,9 +27,13 @@ import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
@@ -43,6 +47,7 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Toolbar;

import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
@@ -65,6 +70,7 @@ import com.android.settings.core.CategoryMixin;
import com.android.settings.core.FeatureFlags;
import com.android.settings.homepage.contextualcards.ContextualCardsFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.PasswordUtils;
import com.android.settingslib.Utils;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;

@@ -431,6 +437,31 @@ public class SettingsHomepageActivity extends FragmentActivity implements
            finish();
            return;
        }

        ActivityInfo targetActivityInfo = null;
        try {
            targetActivityInfo = getPackageManager().getActivityInfo(targetComponentName,
                    /* flags= */ 0);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "Failed to get target ActivityInfo: " + e);
            finish();
            return;
        }

        if (!hasPrivilegedAccess(targetActivityInfo)) {
            if (!targetActivityInfo.exported) {
                Log.e(TAG, "Target Activity is not exported");
                finish();
                return;
            }

            if (!isCallingAppPermitted(targetActivityInfo.permission)) {
                Log.e(TAG, "Calling app must have the permission of deep link Activity");
                finish();
                return;
            }
        }

        targetIntent.setComponent(targetComponentName);

        // To prevent launchDeepLinkIntentToRight again for configuration change.
@@ -472,6 +503,52 @@ public class SettingsHomepageActivity extends FragmentActivity implements
        }
    }

    // Check if calling app has privileged access to launch Activity of activityInfo.
    private boolean hasPrivilegedAccess(ActivityInfo activityInfo) {
        if (TextUtils.equals(PasswordUtils.getCallingAppPackageName(getActivityToken()),
                    getPackageName())) {
            return true;
        }

        int callingUid = -1;
        try {
            callingUid = ActivityManager.getService().getLaunchedFromUid(getActivityToken());
        } catch (RemoteException re) {
            Log.e(TAG, "Not able to get callingUid: " + re);
            return false;
        }

        int targetUid = -1;
        try {
            targetUid = getPackageManager().getApplicationInfo(activityInfo.packageName,
                    /* flags= */ 0).uid;
        } catch (PackageManager.NameNotFoundException nnfe) {
            Log.e(TAG, "Not able to get targetUid: " + nnfe);
            return false;
        }

        // When activityInfo.exported is false, Activity still can be launched if applications have
        // the same user ID.
        if (UserHandle.isSameApp(callingUid, targetUid)) {
            return true;
        }

        // When activityInfo.exported is false, Activity still can be launched if calling app has
        // root or system privilege.
        int callingAppId = UserHandle.getAppId(callingUid);
        if (callingAppId == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID) {
            return true;
        }

        return false;
    }

    @VisibleForTesting
    boolean isCallingAppPermitted(String permission) {
        return TextUtils.isEmpty(permission) || PasswordUtils.isCallingAppPermitted(
                this, getActivityToken(), permission);
    }

    private String getHighlightMenuKey() {
        final Intent intent = getIntent();
        if (intent != null && TextUtils.equals(intent.getAction(),