From 1a8928c3717707fbcc938c53ae117827757bcf26 Mon Sep 17 00:00:00 2001 From: Muntashir Al-Islam Date: Wed, 24 Apr 2024 18:32:12 +0600 Subject: [PATCH] [Refactor] Migrate to Parcel#obtain(IBinder) with compatibility Signed-off-by: Muntashir Al-Islam --- .../AppManager/ipc/AMService.java | 3 +- .../AppManager/ipc/ProxyBinder.java | 6 ++-- .../compat/os/ParcelCompat2.java | 19 ++++++++++++ .../content/pm/BaseParceledListSlice.java | 25 +++++++++++----- .../content/pm/StringParceledListSlice.java | 4 ++- .../server/common/CallerResult.java | 7 +++++ .../server/common/ParcelableUtil.java | 30 +++++++++++++------ .../AppManager/server/ServerHandler.java | 9 ++++-- 8 files changed, 80 insertions(+), 23 deletions(-) create mode 100644 libcore/compat/src/main/java/io/github/muntashirakon/compat/os/ParcelCompat2.java diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/AMService.java b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/AMService.java index fb621d5ec78..28359784fff 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/AMService.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/AMService.java @@ -23,6 +23,7 @@ import io.github.muntashirakon.AppManager.ipc.ps.ProcessEntry; import io.github.muntashirakon.AppManager.ipc.ps.Ps; import io.github.muntashirakon.AppManager.server.common.IRootServiceManager; +import io.github.muntashirakon.compat.os.ParcelCompat2; public class AMService extends RootService { static class IAMServiceImpl extends IAMService.Stub { @@ -87,7 +88,7 @@ private void transactRemote(@NonNull Parcel data, @Nullable Parcel reply) throws int targetCode = data.readInt(); int targetFlags = data.readInt(); - Parcel newData = Parcel.obtain(); + Parcel newData = ParcelCompat2.obtain(targetBinder); try { newData.appendFrom(data, data.dataPosition(), data.dataAvail()); long id = Binder.clearCallingIdentity(); diff --git a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/ProxyBinder.java b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/ProxyBinder.java index ae3dc24e868..d684ce6286c 100644 --- a/app/src/main/java/io/github/muntashirakon/AppManager/ipc/ProxyBinder.java +++ b/app/src/main/java/io/github/muntashirakon/AppManager/ipc/ProxyBinder.java @@ -17,6 +17,7 @@ import java.util.Objects; import io.github.muntashirakon.AppManager.server.common.IRootServiceManager; +import io.github.muntashirakon.compat.os.ParcelCompat2; // Copyright 2020 Rikka public class ProxyBinder implements IBinder { @@ -53,7 +54,8 @@ public ProxyBinder(@NonNull IBinder original) { @Override public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException { if (LocalServices.alive()) { - Parcel newData = Parcel.obtain(); + IBinder targetBinder = LocalServices.getAmService().asBinder(); + Parcel newData = ParcelCompat2.obtain(targetBinder); try { newData.writeInterfaceToken(IRootServiceManager.class.getName()); newData.writeStrongBinder(mOriginal); @@ -61,7 +63,7 @@ public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, newData.writeInt(flags); newData.appendFrom(data, 0, data.dataSize()); // Transact via AMService - LocalServices.getAmService().asBinder().transact(PROXY_BINDER_TRANSACT_CODE, newData, reply, 0); + targetBinder.transact(PROXY_BINDER_TRANSACT_CODE, newData, reply, 0); } finally { newData.recycle(); } diff --git a/libcore/compat/src/main/java/io/github/muntashirakon/compat/os/ParcelCompat2.java b/libcore/compat/src/main/java/io/github/muntashirakon/compat/os/ParcelCompat2.java new file mode 100644 index 00000000000..d7707b17804 --- /dev/null +++ b/libcore/compat/src/main/java/io/github/muntashirakon/compat/os/ParcelCompat2.java @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package io.github.muntashirakon.compat.os; + +import android.os.Build; +import android.os.IBinder; +import android.os.Parcel; + +import androidx.annotation.NonNull; + +public final class ParcelCompat2 { + @NonNull + public static Parcel obtain(@NonNull IBinder binder) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + return Parcel.obtain(binder); + } + return Parcel.obtain(); + } +} diff --git a/libcore/io/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java b/libcore/io/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java index f5500635b03..c387983b655 100644 --- a/libcore/io/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java +++ b/libcore/io/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java @@ -3,6 +3,7 @@ package aosp.android.content.pm; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -10,10 +11,14 @@ import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import io.github.muntashirakon.compat.os.ParcelCompat2; +import io.github.muntashirakon.io.IoUtils; + /** * Transfer a large list of Parcelable objects across an IPC. Splits into * multiple transactions if needed. @@ -29,7 +34,13 @@ abstract class BaseParceledListSlice implements Parcelable { private static final String TAG = "ParceledListSlice"; private static final boolean DEBUG = false; - private static final int MAX_IPC_SIZE = 1024 * 50; /*IoUtils.DEFAULT_BUFFER_SIZE*/ + private static final int MAX_IPC_SIZE; + + static { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes(); + } else MAX_IPC_SIZE = IoUtils.DEFAULT_BUFFER_SIZE; + } private final List mList; @@ -39,7 +50,7 @@ public BaseParceledListSlice(List list) { mList = list; } - BaseParceledListSlice(Parcel p) { + BaseParceledListSlice(@NonNull Parcel p) { // Unlike the Android frameworks, we have no access to certain remote class ClassLoader loader = BaseParceledListSlice.class.getClassLoader(); final int N = p.readInt(); @@ -76,8 +87,8 @@ public BaseParceledListSlice(List list) { final IBinder retriever = p.readStrongBinder(); while (i < N) { if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever); - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); + Parcel data = ParcelCompat2.obtain(retriever); + Parcel reply = ParcelCompat2.obtain(retriever); data.writeInt(i); try { retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0); @@ -100,7 +111,7 @@ public BaseParceledListSlice(List list) { } @SuppressWarnings("unchecked") - private T readCreator(Parcelable.Creator creator, Parcel p, ClassLoader loader) { + private T readCreator(Parcelable.Creator creator, Parcel p, @Nullable ClassLoader loader) { if (creator instanceof Parcelable.ClassLoaderCreator) { Parcelable.ClassLoaderCreator classLoaderCreator = (Parcelable.ClassLoaderCreator) creator; @@ -109,7 +120,7 @@ private T readCreator(Parcelable.Creator creator, Parcel p, ClassLoader loade return (T) creator.createFromParcel(p); } - private static void verifySameType(final Class expected, final Class actual) { + private static void verifySameType(@Nullable final Class expected, @NonNull final Class actual) { if (!actual.equals(expected)) { throw new IllegalArgumentException("Can't unparcel type " + actual.getName() + " in list of type " @@ -192,5 +203,5 @@ protected boolean onTransact(int code, @NonNull Parcel data, Parcel reply, int f protected abstract void writeParcelableCreator(T parcelable, Parcel dest); - protected abstract Parcelable.Creator readParcelableCreator(Parcel from, ClassLoader loader); + protected abstract Parcelable.Creator readParcelableCreator(Parcel from, @Nullable ClassLoader loader); } \ No newline at end of file diff --git a/libcore/io/src/main/java/aosp/android/content/pm/StringParceledListSlice.java b/libcore/io/src/main/java/aosp/android/content/pm/StringParceledListSlice.java index 48e5fc85067..4935d206ecb 100644 --- a/libcore/io/src/main/java/aosp/android/content/pm/StringParceledListSlice.java +++ b/libcore/io/src/main/java/aosp/android/content/pm/StringParceledListSlice.java @@ -5,6 +5,8 @@ import android.os.Parcel; import android.os.Parcelable; +import androidx.annotation.Nullable; + import java.util.Collections; import java.util.List; @@ -43,7 +45,7 @@ protected void writeParcelableCreator(String parcelable, Parcel dest) { } @Override - protected Parcelable.Creator readParcelableCreator(Parcel from, ClassLoader loader) { + protected Parcelable.Creator readParcelableCreator(Parcel from, @Nullable ClassLoader loader) { return Parcel.STRING_CREATOR; } diff --git a/libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/CallerResult.java b/libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/CallerResult.java index 73d8e849926..334057be6ae 100644 --- a/libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/CallerResult.java +++ b/libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/CallerResult.java @@ -6,21 +6,28 @@ import android.os.Parcelable; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; // Copyright 2017 Zheng Li public class CallerResult implements Parcelable { + @Nullable private byte[] mReply; + @Nullable private Throwable mThrowable; + @Nullable private Object mReplyObj; + @Nullable public byte[] getReply() { return mReply; } + @Nullable public Throwable getThrowable() { return mThrowable; } + @Nullable public Object getReplyObj() { if (mReplyObj == null && mReply != null) { mReplyObj = ParcelableUtil.readValue(mReply); diff --git a/libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ParcelableUtil.java b/libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ParcelableUtil.java index 17644220e68..58c673f2e05 100644 --- a/libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ParcelableUtil.java +++ b/libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ParcelableUtil.java @@ -6,19 +6,26 @@ import android.os.Parcelable; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.jetbrains.annotations.Contract; // Copyright 2017 Zheng Li public class ParcelableUtil { @NonNull public static byte[] marshall(@NonNull Parcelable parcelable) { Parcel parcel = Parcel.obtain(); - parcelable.writeToParcel(parcel, 0); - byte[] bytes = parcel.marshall(); - parcel.recycle(); - return bytes; + try { + parcelable.writeToParcel(parcel, 0); + return parcel.marshall(); + } finally { + parcel.recycle(); + } } - public static T unmarshall(byte[] bytes, Parcelable.Creator creator) { + @Contract("!null,_ -> !null") + @Nullable + public static T unmarshall(@Nullable byte[] bytes, @NonNull Parcelable.Creator creator) { if (bytes == null) { return null; } @@ -26,7 +33,9 @@ public static T unmarshall(byte[] bytes, Parcelable.Creat return creator.createFromParcel(parcel); } - public static Parcel unmarshall(byte[] bytes) { + @Contract("!null -> !null") + @Nullable + public static Parcel unmarshall(@Nullable byte[] bytes) { if (bytes == null) { return null; } @@ -36,13 +45,16 @@ public static Parcel unmarshall(byte[] bytes) { return parcel; } + @Nullable public static Object readValue(byte[] bytes) { if (bytes == null) { return null; } Parcel unmarshall = unmarshall(bytes); - Object o = unmarshall.readValue(ParcelableUtil.class.getClassLoader()); - unmarshall.recycle(); - return o; + try { + return unmarshall.readValue(ParcelableUtil.class.getClassLoader()); + } finally { + unmarshall.recycle(); + } } } \ No newline at end of file diff --git a/server/src/main/java/io/github/muntashirakon/AppManager/server/ServerHandler.java b/server/src/main/java/io/github/muntashirakon/AppManager/server/ServerHandler.java index ccce5222238..fdd8f7b8050 100644 --- a/server/src/main/java/io/github/muntashirakon/AppManager/server/ServerHandler.java +++ b/server/src/main/java/io/github/muntashirakon/AppManager/server/ServerHandler.java @@ -134,9 +134,12 @@ public void onMessage(@NonNull byte[] bytes) { Shell.Result shellResult = shell.exec(shellCaller.getCommand()); result = new CallerResult(); Parcel parcel = Parcel.obtain(); - parcel.writeValue(shellResult); - result.setReply(parcel.marshall()); - parcel.recycle(); + try { + parcel.writeValue(shellResult); + result.setReply(parcel.marshall()); + } finally { + parcel.recycle(); + } } LifecycleAgent.sServerInfo.successCount++; } catch (Throwable e) {