diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 876e4014ba459..3289304a0df48 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1005,6 +1005,11 @@ public final class ActivityThread extends ClientTransactionHandler RemoteCallback finishCallback; } + static final class DumpResourcesData { + public ParcelFileDescriptor fd; + public RemoteCallback finishCallback; + } + static final class UpdateCompatibilityData { String pkg; CompatibilityInfo info; @@ -1316,6 +1321,20 @@ public final class ActivityThread extends ClientTransactionHandler sendMessage(H.SCHEDULE_CRASH, args, typeId); } + @Override + public void dumpResources(ParcelFileDescriptor fd, RemoteCallback callback) { + DumpResourcesData data = new DumpResourcesData(); + try { + data.fd = fd.dup(); + data.finishCallback = callback; + sendMessage(H.DUMP_RESOURCES, data, 0, 0, false /*async*/); + } catch (IOException e) { + Slog.w(TAG, "dumpResources failed", e); + } finally { + IoUtils.closeQuietly(fd); + } + } + public void dumpActivity(ParcelFileDescriptor pfd, IBinder activitytoken, String prefix, String[] args) { DumpComponentInfo data = new DumpComponentInfo(); @@ -2039,6 +2058,7 @@ public final class ActivityThread extends ClientTransactionHandler public static final int UPDATE_UI_TRANSLATION_STATE = 163; public static final int SET_CONTENT_CAPTURE_OPTIONS_CALLBACK = 164; public static final int DUMP_GFXINFO = 165; + public static final int DUMP_RESOURCES = 166; public static final int INSTRUMENT_WITHOUT_RESTART = 170; public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171; @@ -2092,6 +2112,7 @@ public final class ActivityThread extends ClientTransactionHandler case INSTRUMENT_WITHOUT_RESTART: return "INSTRUMENT_WITHOUT_RESTART"; case FINISH_INSTRUMENTATION_WITHOUT_RESTART: return "FINISH_INSTRUMENTATION_WITHOUT_RESTART"; + case DUMP_RESOURCES: return "DUMP_RESOURCES"; } } return Integer.toString(code); @@ -2207,6 +2228,9 @@ public final class ActivityThread extends ClientTransactionHandler case DUMP_HEAP: handleDumpHeap((DumpHeapData) msg.obj); break; + case DUMP_RESOURCES: + handleDumpResources((DumpResourcesData) msg.obj); + break; case DUMP_ACTIVITY: handleDumpActivity((DumpComponentInfo)msg.obj); break; @@ -4585,6 +4609,23 @@ public final class ActivityThread extends ClientTransactionHandler } } + private void handleDumpResources(DumpResourcesData info) { + final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); + try { + PrintWriter pw = new FastPrintWriter(new FileOutputStream( + info.fd.getFileDescriptor())); + + Resources.dumpHistory(pw, ""); + pw.flush(); + if (info.finishCallback != null) { + info.finishCallback.sendResult(null); + } + } finally { + IoUtils.closeQuietly(info.fd); + StrictMode.setThreadPolicy(oldPolicy); + } + } + private void handleDumpActivity(DumpComponentInfo info) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); try { diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 1714229486e4a..77657d58cc4c1 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -113,6 +113,7 @@ oneway interface IApplicationThread { in ParcelFileDescriptor fd, in RemoteCallback finishCallback); void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix, in String[] args); + void dumpResources(in ParcelFileDescriptor fd, in RemoteCallback finishCallback); void clearDnsCache(); void updateHttpProxy(); void setCoreSettings(in Bundle coreSettings); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 0b8a8a23aee44..2f0608308635a 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -5635,6 +5635,15 @@ public abstract class Context { */ public static final String OVERLAY_SERVICE = "overlay"; + /** + * Use with {@link #getSystemService(String)} to manage resources. + * + * @see #getSystemService(String) + * @see com.android.server.resources.ResourcesManagerService + * @hide + */ + public static final String RESOURCES_SERVICE = "resources"; + /** * Use with {@link #getSystemService(String)} to retrieve a * {android.os.IIdmap2} for managing idmap files (used by overlay diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java index 6fd2d05ad1357..7a5ac8ede4a42 100644 --- a/core/java/android/content/res/ApkAssets.java +++ b/core/java/android/content/res/ApkAssets.java @@ -28,6 +28,7 @@ import com.android.internal.annotations.GuardedBy; import java.io.FileDescriptor; import java.io.IOException; +import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -438,6 +439,12 @@ public final class ApkAssets { } } + void dump(PrintWriter pw, String prefix) { + pw.println(prefix + "class=" + getClass()); + pw.println(prefix + "debugName=" + getDebugName()); + pw.println(prefix + "assetPath=" + getAssetPath()); + } + private static native long nativeLoad(@FormatType int format, @NonNull String path, @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException; private static native long nativeLoadEmpty(@PropertyFlags int flags, diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index bfd9fd0a4ef9c..a05f5c927b297 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -43,6 +43,7 @@ import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.PrintWriter; import java.lang.ref.Reference; import java.util.ArrayList; import java.util.Arrays; @@ -1531,6 +1532,15 @@ public final class AssetManager implements AutoCloseable { } } + synchronized void dump(PrintWriter pw, String prefix) { + pw.println(prefix + "class=" + getClass()); + pw.println(prefix + "apkAssets="); + for (int i = 0; i < mApkAssets.length; i++) { + pw.println(prefix + i); + mApkAssets[i].dump(pw, prefix + " "); + } + } + // AssetManager setup native methods. private static native long nativeCreate(); private static native void nativeDestroy(long ptr); diff --git a/core/java/android/content/res/IResourcesManager.aidl b/core/java/android/content/res/IResourcesManager.aidl new file mode 100644 index 0000000000000..d1373788f1c58 --- /dev/null +++ b/core/java/android/content/res/IResourcesManager.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 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.res; + +import android.os.RemoteCallback; + +/** + * Api for getting information about resources. + * + * {@hide} + */ +interface IResourcesManager { + boolean dumpResources(in String process, + in ParcelFileDescriptor fd, + in RemoteCallback finishCallback); +} \ No newline at end of file diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 5fd0d841f0e38..ebef0535f0779 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -53,6 +53,7 @@ import android.graphics.drawable.Drawable.ConstantState; import android.graphics.drawable.DrawableInflater; import android.os.Build; import android.os.Bundle; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.AttributeSet; import android.util.DisplayMetrics; @@ -78,11 +79,15 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.InputStream; +import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; /** * Class for accessing an application's resources. This sits on top of the @@ -172,6 +177,11 @@ public class Resources { private int mBaseApkAssetsSize; + /** @hide */ + private static Set sResourcesHistory = Collections.synchronizedSet( + Collections.newSetFromMap( + new WeakHashMap<>())); + /** * Returns the most appropriate default theme for the specified target SDK version. *