diff --git a/app/src/main/aidl/aosp/android/content/pm/ParceledListSlice.aidl b/libcore/io/src/main/aidl/aosp/android/content/pm/ParceledListSlice.aidl similarity index 100% rename from app/src/main/aidl/aosp/android/content/pm/ParceledListSlice.aidl rename to libcore/io/src/main/aidl/aosp/android/content/pm/ParceledListSlice.aidl diff --git a/app/src/main/aidl/aosp/android/content/pm/StringParceledListSlice.aidl b/libcore/io/src/main/aidl/aosp/android/content/pm/StringParceledListSlice.aidl similarity index 100% rename from app/src/main/aidl/aosp/android/content/pm/StringParceledListSlice.aidl rename to libcore/io/src/main/aidl/aosp/android/content/pm/StringParceledListSlice.aidl diff --git a/libcore/io/src/main/aidl/io/github/muntashirakon/io/IFileSystemService.aidl b/libcore/io/src/main/aidl/io/github/muntashirakon/io/IFileSystemService.aidl index 51e4e22e6a4..1c4a2e3910e 100644 --- a/libcore/io/src/main/aidl/io/github/muntashirakon/io/IFileSystemService.aidl +++ b/libcore/io/src/main/aidl/io/github/muntashirakon/io/IFileSystemService.aidl @@ -2,6 +2,7 @@ package io.github.muntashirakon.io; +import aosp.android.content.pm.StringParceledListSlice; import io.github.muntashirakon.io.IOResult; // Copyright 2022 John "topjohnwu" Wu @@ -18,7 +19,7 @@ interface IFileSystemService { long length(String path); /* (err, bool) */ IOResult createNewFile(String path); boolean delete(String path); - String[] list(String path); + StringParceledListSlice list(String path); boolean mkdir(String path); boolean mkdirs(String path); boolean renameTo(String path, String dest); diff --git a/app/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java b/libcore/io/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java similarity index 96% rename from app/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java rename to libcore/io/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java index deb0fe0225e..f5500635b03 100644 --- a/app/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java +++ b/libcore/io/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later +// SPDX-License-Identifier: GPL-3.0-or-later package aosp.android.content.pm; @@ -14,12 +14,10 @@ import java.util.ArrayList; import java.util.List; -import io.github.muntashirakon.io.IoUtils; - /** * Transfer a large list of Parcelable objects across an IPC. Splits into * multiple transactions if needed. - * + *

* Caveat: for efficiency and security, all elements must be the same concrete type. * In order to avoid writing the class name of each object, we must ensure that * each object is the same type, or else unparceling then reparceling the data may yield @@ -31,7 +29,7 @@ abstract class BaseParceledListSlice implements Parcelable { private static final String TAG = "ParceledListSlice"; private static final boolean DEBUG = false; - private static final int MAX_IPC_SIZE = IoUtils.DEFAULT_BUFFER_SIZE; + private static final int MAX_IPC_SIZE = 1024 * 50; /*IoUtils.DEFAULT_BUFFER_SIZE*/ private final List mList; @@ -69,7 +67,7 @@ public BaseParceledListSlice(List list) { mList.add(parcelable); - if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1)); + if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size() - 1)); i++; } if (i >= N) { @@ -93,7 +91,7 @@ public BaseParceledListSlice(List list) { mList.add(parcelable); - if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1)); + if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size() - 1)); i++; } reply.recycle(); diff --git a/libcore/io/src/main/java/aosp/android/content/pm/ParcelUtils.java b/libcore/io/src/main/java/aosp/android/content/pm/ParcelUtils.java new file mode 100644 index 00000000000..23e8748cfb5 --- /dev/null +++ b/libcore/io/src/main/java/aosp/android/content/pm/ParcelUtils.java @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package aosp.android.content.pm; + +import android.os.BadParcelableException; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; + +public class ParcelUtils { + private static final String TAG = ParcelUtils.class.getSimpleName(); + + public static void writeParcelableCreator(@NonNull T parcelable, @NonNull Parcel dest) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + dest.writeParcelableCreator((Parcelable) parcelable); + } else { + String name = parcelable.getClass().getName(); + dest.writeString(name); + } + } + + // Cache of previously looked up CREATOR.createFromParcel() methods for + // particular classes. Keys are the names of the classes, values are + // Method objects. + private static final HashMap>> mCreators = new HashMap<>(); + + @Nullable + public static Parcelable.Creator readParcelableCreator(@NonNull Parcel from, @Nullable ClassLoader loader) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + return from.readParcelableCreator(loader); + } + String name = from.readString(); + if (name == null) { + return null; + } + Parcelable.Creator creator; + synchronized (mCreators) { + HashMap> map = mCreators.get(loader); + if (map == null) { + map = new HashMap<>(); + mCreators.put(loader, map); + } + creator = map.get(name); + if (creator == null) { + try { + // If loader == null, explicitly emulate Class.forName(String) "caller + // classloader" behavior. + ClassLoader parcelableClassLoader = (loader == null ? from.getClass().getClassLoader() : loader); + // Avoid initializing the Parcelable class until we know it implements + // Parcelable and has the necessary CREATOR field. + Class parcelableClass = Class.forName(name, false /* initialize */, + parcelableClassLoader); + if (!Parcelable.class.isAssignableFrom(parcelableClass)) { + throw new BadParcelableException("Parcelable protocol requires that the " + + "class implements Parcelable"); + } + Field f = parcelableClass.getField("CREATOR"); + if ((f.getModifiers() & Modifier.STATIC) == 0) { + throw new BadParcelableException("Parcelable protocol requires " + + "the CREATOR object to be static on class " + name); + } + Class creatorType = f.getType(); + if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) { + // Fail before calling Field.get(), not after, to avoid initializing + // parcelableClass unnecessarily. + throw new BadParcelableException("Parcelable protocol requires a " + + "Parcelable.Creator object called " + + "CREATOR on class " + name); + } + creator = (Parcelable.Creator) f.get(null); + } catch (IllegalAccessException e) { + Log.e(TAG, "Illegal access when unmarshalling: " + name, e); + throw new BadParcelableException( + "IllegalAccessException when unmarshalling: " + name); + } catch (ClassNotFoundException e) { + Log.e(TAG, "Class not found when unmarshalling: " + name, e); + throw new BadParcelableException("ClassNotFoundException when unmarshalling: " + name); + } catch (NoSuchFieldException e) { + throw new BadParcelableException("Parcelable protocol requires a " + + "Parcelable.Creator object called " + + "CREATOR on class " + name); + } + if (creator == null) { + throw new BadParcelableException("Parcelable protocol requires a " + + "non-null Parcelable.Creator object called " + + "CREATOR on class " + name); + } + map.put(name, creator); + } + } + + return creator; + } +} diff --git a/app/src/main/java/aosp/android/content/pm/ParceledListSlice.java b/libcore/io/src/main/java/aosp/android/content/pm/ParceledListSlice.java similarity index 94% rename from app/src/main/java/aosp/android/content/pm/ParceledListSlice.java rename to libcore/io/src/main/java/aosp/android/content/pm/ParceledListSlice.java index d98d71ad8c3..af49d0884f8 100644 --- a/app/src/main/java/aosp/android/content/pm/ParceledListSlice.java +++ b/libcore/io/src/main/java/aosp/android/content/pm/ParceledListSlice.java @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later +// SPDX-License-Identifier: GPL-3.0-or-later package aosp.android.content.pm; @@ -10,8 +10,6 @@ import java.util.Collections; import java.util.List; -import io.github.muntashirakon.util.ParcelUtils; - /** * Transfer a large list of Parcelable objects across an IPC. Splits into * multiple transactions if needed. diff --git a/app/src/main/java/aosp/android/content/pm/StringParceledListSlice.java b/libcore/io/src/main/java/aosp/android/content/pm/StringParceledListSlice.java similarity index 96% rename from app/src/main/java/aosp/android/content/pm/StringParceledListSlice.java rename to libcore/io/src/main/java/aosp/android/content/pm/StringParceledListSlice.java index 33b0681db20..48e5fc85067 100644 --- a/app/src/main/java/aosp/android/content/pm/StringParceledListSlice.java +++ b/libcore/io/src/main/java/aosp/android/content/pm/StringParceledListSlice.java @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later +// SPDX-License-Identifier: GPL-3.0-or-later package aosp.android.content.pm; diff --git a/libcore/io/src/main/java/io/github/muntashirakon/io/FileSystemService.java b/libcore/io/src/main/java/io/github/muntashirakon/io/FileSystemService.java index eba3d8c920b..4e21dab84dd 100644 --- a/libcore/io/src/main/java/io/github/muntashirakon/io/FileSystemService.java +++ b/libcore/io/src/main/java/io/github/muntashirakon/io/FileSystemService.java @@ -23,9 +23,11 @@ import java.io.File; import java.io.IOException; +import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import aosp.android.content.pm.StringParceledListSlice; import io.github.muntashirakon.compat.system.OsCompat; import io.github.muntashirakon.compat.system.StructTimespec; @@ -109,8 +111,9 @@ public boolean delete(String path) { } @Override - public String[] list(String path) { - return mCache.get(path).list(); + public StringParceledListSlice list(String path) { + String[] list = mCache.get(path).list(); + return list != null ? new StringParceledListSlice(Arrays.asList(list)) : null; } @Override diff --git a/libcore/io/src/main/java/io/github/muntashirakon/io/RemoteFile.java b/libcore/io/src/main/java/io/github/muntashirakon/io/RemoteFile.java index c5590ee58b2..989b6497a35 100644 --- a/libcore/io/src/main/java/io/github/muntashirakon/io/RemoteFile.java +++ b/libcore/io/src/main/java/io/github/muntashirakon/io/RemoteFile.java @@ -15,6 +15,8 @@ import java.io.FileOutputStream; import java.io.IOException; +import aosp.android.content.pm.StringParceledListSlice; + // Copyright 2022 John "topjohnwu" Wu // Copyright 2022 Muntashir Al-Islam class RemoteFile extends FileImpl { @@ -313,7 +315,8 @@ public void deleteOnExit() { @Override public String[] list() { try { - return fs.list(getPath()); + StringParceledListSlice list = fs.list(getPath()); + return list != null ? list.getList().toArray(new String[0]) : null; } catch (RemoteException e) { return null; } diff --git a/libcore/ui/src/main/java/io/github/muntashirakon/util/ParcelUtils.java b/libcore/ui/src/main/java/io/github/muntashirakon/util/ParcelUtils.java index b13a3a4d64c..1ab827fa9b3 100644 --- a/libcore/ui/src/main/java/io/github/muntashirakon/util/ParcelUtils.java +++ b/libcore/ui/src/main/java/io/github/muntashirakon/util/ParcelUtils.java @@ -2,24 +2,16 @@ package io.github.muntashirakon.util; -import android.os.BadParcelableException; -import android.os.Build; import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.collection.ArraySet; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; public class ParcelUtils { - private static final String TAG = ParcelUtils.class.getSimpleName(); - /** * Write an array set to the parcel. * @@ -70,86 +62,4 @@ public static Map readMap(@NonNull Parcel parcel, @Nullable ClassLo } return map; } - - public static void writeParcelableCreator(@NonNull T parcelable, @NonNull Parcel dest) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - dest.writeParcelableCreator((Parcelable) parcelable); - } else { - String name = parcelable.getClass().getName(); - dest.writeString(name); - } - } - - // Cache of previously looked up CREATOR.createFromParcel() methods for - // particular classes. Keys are the names of the classes, values are - // Method objects. - private static final HashMap>> mCreators = new HashMap<>(); - - @Nullable - public static Parcelable.Creator readParcelableCreator(@NonNull Parcel from, @Nullable ClassLoader loader) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - return from.readParcelableCreator(loader); - } - String name = from.readString(); - if (name == null) { - return null; - } - Parcelable.Creator creator; - synchronized (mCreators) { - HashMap> map = mCreators.get(loader); - if (map == null) { - map = new HashMap<>(); - mCreators.put(loader, map); - } - creator = map.get(name); - if (creator == null) { - try { - // If loader == null, explicitly emulate Class.forName(String) "caller - // classloader" behavior. - ClassLoader parcelableClassLoader = (loader == null ? from.getClass().getClassLoader() : loader); - // Avoid initializing the Parcelable class until we know it implements - // Parcelable and has the necessary CREATOR field. - Class parcelableClass = Class.forName(name, false /* initialize */, - parcelableClassLoader); - if (!Parcelable.class.isAssignableFrom(parcelableClass)) { - throw new BadParcelableException("Parcelable protocol requires that the " - + "class implements Parcelable"); - } - Field f = parcelableClass.getField("CREATOR"); - if ((f.getModifiers() & Modifier.STATIC) == 0) { - throw new BadParcelableException("Parcelable protocol requires " - + "the CREATOR object to be static on class " + name); - } - Class creatorType = f.getType(); - if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) { - // Fail before calling Field.get(), not after, to avoid initializing - // parcelableClass unnecessarily. - throw new BadParcelableException("Parcelable protocol requires a " - + "Parcelable.Creator object called " - + "CREATOR on class " + name); - } - creator = (Parcelable.Creator) f.get(null); - } catch (IllegalAccessException e) { - Log.e(TAG, "Illegal access when unmarshalling: " + name, e); - throw new BadParcelableException( - "IllegalAccessException when unmarshalling: " + name); - } catch (ClassNotFoundException e) { - Log.e(TAG, "Class not found when unmarshalling: " + name, e); - throw new BadParcelableException("ClassNotFoundException when unmarshalling: " + name); - } catch (NoSuchFieldException e) { - throw new BadParcelableException("Parcelable protocol requires a " - + "Parcelable.Creator object called " - + "CREATOR on class " + name); - } - if (creator == null) { - throw new BadParcelableException("Parcelable protocol requires a " - + "non-null Parcelable.Creator object called " - + "CREATOR on class " + name); - } - map.put(name, creator); - } - } - - return creator; - } }