From 691cacfa325ca6d9fb0e94ec1b1b1e24ba79f324 Mon Sep 17 00:00:00 2001 From: frknkrc44 Date: Tue, 9 Sep 2025 05:37:32 +0300 Subject: [PATCH] Revert channel message template to old one, improve multi-user support (WIP) --- .github/workflows/main.yml | 208 +++++++++--------- .github/workflows/pull_request.yml | 2 +- .../hidemyapplist/xposed/HMAService.kt | 9 +- .../xposed/hook/PmsHookTargetBase.kt | 12 +- 4 files changed, 117 insertions(+), 114 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3ebfb29..6cfecb5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,104 +1,104 @@ -name: Main - -on: - push: - branches: [ master ] - paths-ignore: - - '.github/ISSUE_TEMPLATE/**' - - '.github/workflows/issue.yml' - - '.github/workflows/pull_request.yml' - - '**.md' - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -jobs: - build: - name: Build on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ ubuntu-latest ] - if: ${{ !startsWith(github.event.head_commit.message, '[skip ci]') }} - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: 'recursive' - fetch-depth: 0 - - - name: Gradle wrapper validation - uses: gradle/wrapper-validation-action@v3 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '21' - - - name: Write key - if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master' - run: | - echo officialBuild=true >> local.properties - echo buildWithGitSuffix=true >> local.properties - echo storePassword='${{ secrets.KEY_STORE_PASSWORD }}' >> local.properties - echo keyAlias='${{ secrets.ALIAS }}' >> local.properties - echo keyPassword='${{ secrets.ALIAS_KEY_PASSWORD }}' >> local.properties - echo fileDir=`pwd`/key.jks >> local.properties - echo "${{ secrets.KEY_STORE }}" | base64 --decode > key.jks - - - name: Cache gradle - uses: actions/cache@v4 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: ${{ runner.os }}-gradle- - - - name: Gradle prebuild - run: | - ./gradlew prebuild - - - name: Build all - id: buildAll - run: | - ./gradlew assemble - echo "releaseName=$(ls app/build/outputs/apk/release/*.apk | awk -F '(/|.apk)' '{print $5}')" >> $GITHUB_OUTPUT - echo "debugName=$(ls app/build/outputs/apk/debug/*.apk | awk -F '(/|.apk)' '{print $5}')" >> $GITHUB_OUTPUT - - - name: Upload release - if: success() - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.buildAll.outputs.releaseName }} - path: "app/build/outputs/apk/release/*.apk" - - - name: Upload debug - if: success() - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.buildAll.outputs.debugName }} - path: "app/build/outputs/apk/debug/*.apk" - - - name: Upload mappings - uses: actions/upload-artifact@v4 - with: - name: mappings - path: "app/build/outputs/mapping/release" - - - name: Post to channel - if: ${{ github.event_name != 'pull_request' && success() && github.ref == 'refs/heads/master' }} - env: - CHANNEL_ID: ${{ secrets.TELEGRAM_CHANNEL }} - BOT_TOKEN: ${{ secrets.TELEGRAM_TOKEN }} - COMMIT_URL: ${{ github.event.head_commit.url }} - COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - run: | - OUTPUT="app/build/outputs/apk/" - export release=$(find $OUTPUT -name "*-release.apk") - export debug=$(find $OUTPUT -name "*-debug.apk") - ESCAPED=`python3 -c 'import json,os,urllib.parse; msg = json.dumps(os.environ["COMMIT_MESSAGE"]); url = json.dumps(os.environ["COMMIT_URL"]); print(urllib.parse.quote((msg if len(msg) <= 512 else (msg[:512] + "...") + "\nURL: " + url)))'` - curl -v "https://api.telegram.org/bot${BOT_TOKEN}/sendMediaGroup?chat_id=${CHANNEL_ID}&media=%5B%7B%22type%22:%22document%22,%20%22media%22:%22attach://release%22%7D,%7B%22type%22:%22document%22,%20%22media%22:%22attach://debug%22,%22caption%22:${ESCAPED}%7D%5D" -F release="@$release" -F debug="@$debug" +name: Main + +on: + push: + branches: [ master ] + paths-ignore: + - '.github/ISSUE_TEMPLATE/**' + - '.github/workflows/issue.yml' + - '.github/workflows/pull_request.yml' + - '**.md' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + build: + name: Build on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest ] + if: ${{ !startsWith(github.event.head_commit.message, '[skip ci]') }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: 'recursive' + fetch-depth: 0 + + - name: Gradle wrapper validation + uses: gradle/wrapper-validation-action@v3 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + + - name: Write key + if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master' + run: | + echo officialBuild=true >> local.properties + echo buildWithGitSuffix=true >> local.properties + echo storePassword='${{ secrets.KEY_STORE_PASSWORD }}' >> local.properties + echo keyAlias='${{ secrets.ALIAS }}' >> local.properties + echo keyPassword='${{ secrets.ALIAS_KEY_PASSWORD }}' >> local.properties + echo fileDir=`pwd`/key.jks >> local.properties + echo "${{ secrets.KEY_STORE }}" | base64 --decode > key.jks + + - name: Cache gradle + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} + restore-keys: ${{ runner.os }}-gradle- + + - name: Gradle prebuild + run: | + ./gradlew prebuild + + - name: Build all + id: buildAll + run: | + ./gradlew assemble + echo "releaseName=$(ls app/build/outputs/apk/release/*.apk | awk -F '(/|.apk)' '{print $5}')" >> $GITHUB_OUTPUT + echo "debugName=$(ls app/build/outputs/apk/debug/*.apk | awk -F '(/|.apk)' '{print $5}')" >> $GITHUB_OUTPUT + + - name: Upload release + if: success() + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.buildAll.outputs.releaseName }} + path: "app/build/outputs/apk/release/*.apk" + + - name: Upload debug + if: success() + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.buildAll.outputs.debugName }} + path: "app/build/outputs/apk/debug/*.apk" + + - name: Upload mappings + uses: actions/upload-artifact@v4 + with: + name: mappings + path: "app/build/outputs/mapping/release" + + - name: Post to channel + if: ${{ github.event_name != 'pull_request' && success() && github.ref == 'refs/heads/master' }} + env: + CHANNEL_ID: ${{ secrets.TELEGRAM_CHANNEL }} + BOT_TOKEN: ${{ secrets.TELEGRAM_TOKEN }} + COMMIT_URL: ${{ github.event.head_commit.url }} + COMMIT_MESSAGE: ${{ github.event.head_commit.message }} + run: | + OUTPUT="app/build/outputs/apk/" + export release=$(find $OUTPUT -name "*-release.apk") + export debug=$(find $OUTPUT -name "*-debug.apk") + ESCAPED=`python3 -c 'import json,os,urllib.parse; msg = json.dumps(os.environ["COMMIT_MESSAGE"]); print(urllib.parse.quote(msg if len(msg) <= 1024 else json.dumps(os.environ["COMMIT_URL"])))'` + curl -v "https://api.telegram.org/bot${BOT_TOKEN}/sendMediaGroup?chat_id=${CHANNEL_ID}&media=%5B%7B%22type%22:%22document%22,%20%22media%22:%22attach://release%22%7D,%7B%22type%22:%22document%22,%20%22media%22:%22attach://debug%22,%22caption%22:${ESCAPED}%7D%5D" -F release="@$release" -F debug="@$debug" \ No newline at end of file diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index b8c1965..f428b72 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -57,4 +57,4 @@ jobs: id: buildDebug run: | ./gradlew :app:assembleDebug - echo "debugName=$(ls app/build/apk/debug/HMA*-debug.apk | awk -F '(/|.apk)' '{print $6}')" >> $GITHUB_OUTPUT + echo "debugName=$(ls app/build/outputs/apk/debug/*.apk | awk -F '(/|.apk)' '{print $6}')" >> $GITHUB_OUTPUT diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt index 1b61cae..9777bf0 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt +++ b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/HMAService.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.IPackageManager import android.os.Build +import android.os.UserHandle import icu.nullptr.hidemyapplist.common.AppPresets import icu.nullptr.hidemyapplist.common.Constants import icu.nullptr.hidemyapplist.common.IHMAService @@ -192,7 +193,7 @@ class HMAService(val pms: IPackageManager) : IHMAService.Stub() { return appConfig.useWhitelist } - fun shouldHideInstallationSource(caller: String?, query: String?): Int { + fun shouldHideInstallationSource(caller: String?, query: String?, user: UserHandle): Int { if (caller == null || query == null) return 0 val appConfig = config.scope[caller] ?: return 0 if (!appConfig.hideInstallationSource) return 0 @@ -200,11 +201,11 @@ class HMAService(val pms: IPackageManager) : IHMAService.Stub() { if (caller == query && appConfig.excludeTargetInstallationSource) return 0 try { - val uid = Utils.getPackageUidCompat(pms, query, 0L, 0) - logD(TAG, "@shouldHideInstallationSource UID for $caller -> $query: $uid") + val uid = Utils.getPackageUidCompat(pms, query, 0L, user.hashCode()) + logD(TAG, "@shouldHideInstallationSource UID for $caller (${user.hashCode()}) -> $query: $uid") if (uid < 0) return 0 // invalid package installation source request } catch (e: Throwable) { - logD(TAG, "@shouldHideInstallationSource UID error", e) + logD(TAG, "@shouldHideInstallationSource UID error for $caller (${user.hashCode()})", e) return 0 } diff --git a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt index 49b2402..b04c5fb 100644 --- a/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt +++ b/xposed/src/main/java/icu/nullptr/hidemyapplist/xposed/hook/PmsHookTargetBase.kt @@ -34,15 +34,16 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework findMethodOrNull(service.pms::class.java, findSuper = true) { name == "getInstallSourceInfo" }?.hookBefore { param -> - val targetApp = param.args[0] as String? + val query = param.args[0] as String? + val user = Binder.getCallingUserHandle() val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore val callingApps = Utils.binderLocalScope { service.pms.getPackagesForUid(callingUid) } ?: return@hookBefore for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, targetApp)) { + when (service.shouldHideInstallationSource(caller, query, user)) { 1 -> param.result = fakeUserPackageInstallInfo 2 -> param.result = fakeSystemPackageInstallInfo else -> continue @@ -59,15 +60,16 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework hooks += findMethod(service.pms::class.java, findSuper = true) { name == "getInstallerPackageName" }.hookBefore { param -> - val targetApp = param.args[0] as String? + val query = param.args[0] as String? + val user = Binder.getCallingUserHandle() val callingUid = Binder.getCallingUid() if (callingUid == Constants.UID_SYSTEM) return@hookBefore val callingApps = Utils.binderLocalScope { service.pms.getPackagesForUid(callingUid) } ?: return@hookBefore for (caller in callingApps) { - when (service.shouldHideInstallationSource(caller, targetApp)) { + when (service.shouldHideInstallationSource(caller, query, user)) { 1 -> param.result = VENDING_PACKAGE_NAME 2 -> param.result = null else -> continue @@ -83,4 +85,4 @@ abstract class PmsHookTargetBase(protected val service: HMAService) : IFramework hooks.forEach(XC_MethodHook.Unhook::unhook) hooks.clear() } -} \ No newline at end of file +}