Add proguard annotations for code used by native/reflection (#1207)

Filament references a few classes from native code and by reflections,
so when proguarding binaries we typically had to add an exception for
filament to make it run:

-keep class com.google.android.filament.** {*;}

In a compiled .dex file, the filament namespace takes about 120kb
(before compression), even if the classes aren't used.

To enable proguarding and stripping out unused filament classes,
introduce a UsedByNative and UsedByReflection annotation to explicitly
mark classes that need to be kept in the dex, so that the rest can be
potentially stripped out.

In my testing, this reduces the filament namespace in the .dex from
120kb->40kb, which translates to about 30kb apk size savings after
compression.
This commit is contained in:
Jeff McGlynn
2019-05-20 21:02:54 -07:00
committed by Romain Guy
parent e2c3dfd341
commit 9fe60a6368
8 changed files with 125 additions and 14 deletions

View File

@@ -5,17 +5,18 @@
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# JNI is an entry point that's hard to keep track of, so there's
# an annotation to mark fields and methods used by native code.
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# Keep the annotations that proguard needs to process.
-keep class com.google.android.filament.proguard.UsedBy*
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# Just because native code accesses members of a class, does not mean that the
# class itself needs to be annotated - only annotate classes that are
# referenced themselves in native code.
-keep @com.google.android.filament.proguard.UsedBy* class * {
<init>();
}
-keepclassmembers class * {
@com.google.android.filament.proguard.UsedBy* *;
}

View File

@@ -16,6 +16,8 @@
package com.google.android.filament;
import com.google.android.filament.proguard.UsedByReflection;
import android.support.annotation.NonNull;
public class Engine {
@@ -270,6 +272,7 @@ public class Engine {
Fence.waitAndDestroy(createFence(Fence.Type.HARD), Fence.Mode.FLUSH);
}
@UsedByReflection("TextureHelper.java")
long getNativeObject() {
if (mNativeObject == 0) {
throw new IllegalStateException("Calling method on destroyed Engine");

View File

@@ -19,6 +19,7 @@ package com.google.android.filament;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Size;
import com.google.android.filament.proguard.UsedByNative;
import java.nio.Buffer;
import java.util.ArrayList;
@@ -69,6 +70,7 @@ public class Material {
FRONT_AND_BACK
}
@UsedByNative("Material.cpp")
public static class Parameter {
public enum Type {
BOOL,
@@ -101,8 +103,8 @@ public class Material {
DEFAULT
}
// Used by native code
@SuppressWarnings("unused")
@UsedByNative("Material.cpp")
private static final int SAMPLER_OFFSET = Type.MAT4.ordinal() + 1;
@NonNull
@@ -122,8 +124,8 @@ public class Material {
this.count = count;
}
// Used by native code
@SuppressWarnings("unused")
@UsedByNative("Material.cpp")
private static void add(@NonNull List<Parameter> parameters, @NonNull String name,
@IntRange(from = 0) int type, @IntRange(from = 0) int precision,
@IntRange(from = 1) int count) {

View File

@@ -17,6 +17,7 @@
package com.google.android.filament;
import android.support.annotation.NonNull;
import com.google.android.filament.proguard.UsedByNative;
import java.nio.Buffer;
import java.nio.ByteBuffer;
@@ -26,6 +27,7 @@ import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.ShortBuffer;
@UsedByNative("NioUtils.cpp")
final class NioUtils {
enum BufferType {
@@ -41,18 +43,22 @@ final class NioUtils {
private NioUtils() {
}
@UsedByNative("NioUtils.cpp")
static long getBasePointer(@NonNull Buffer b, long address, int sizeShift) {
return address != 0 ? address + (b.position() << sizeShift) : 0;
}
@UsedByNative("NioUtils.cpp")
static Object getBaseArray(@NonNull Buffer b) {
return b.hasArray() ? b.array() : null;
}
@UsedByNative("NioUtils.cpp")
static int getBaseArrayOffset(@NonNull Buffer b, int sizeShift) {
return b.hasArray() ? ((b.arrayOffset() + b.position()) << sizeShift) : 0;
}
@UsedByNative("NioUtils.cpp")
static int getBufferType(@NonNull Buffer b) {
if (b instanceof ByteBuffer) {
return BufferType.BYTE.ordinal();

View File

@@ -16,6 +16,8 @@
package com.google.android.filament;
import com.google.android.filament.proguard.UsedByReflection;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -470,6 +472,7 @@ public class Texture {
nGenerateMipmaps(getNativeObject(), engine.getNativeObject());
}
@UsedByReflection("TextureHelper.java")
long getNativeObject() {
if (mNativeObject == 0) {
throw new IllegalStateException("Calling method on destroyed Texture");

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2019 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 com.google.android.filament.proguard;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* Annotation used for marking methods and fields that are called from native
* code. Useful for keeping components that would otherwise be removed by
* Proguard. Use the value parameter to mention a file that calls this method.
*
* Note that adding this annotation to a method is not enough to guarantee that
* it is kept - either its class must be referenced elsewhere in the program, or
* the class must be annotated with this as well.
*
* Usage example:<br />
* {@code
* @UsedByNative("NativeCrashHandler.cpp")
public static void reportCrash(int signal, int code, int address) {
...
}
}
*/
@Target({
ElementType.METHOD,
ElementType.FIELD,
ElementType.TYPE,
ElementType.CONSTRUCTOR})
public @interface UsedByNative {
String value();
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2019 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 com.google.android.filament.proguard;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
* Annotation used for marking methods and fields that are called by reflection. Useful for keeping
* components that would otherwise be removed by Proguard. Use the value parameter to mention a file
* that calls this method.
*
* Note that adding this annotation to a method is not enough to guarantee that
* it is kept - either its class must be referenced elsewhere in the program, or
* the class must be annotated with this as well.
*
* Usage example:<br />
* {@code
* @UsedByReflection("PeopleListItemView.java")
public PeopleListItemViewV11(Context context) {
super(context);
}
}
*/
@Target({
ElementType.METHOD,
ElementType.FIELD,
ElementType.TYPE,
ElementType.CONSTRUCTOR})
public @interface UsedByReflection {
String value();
}

View File

@@ -137,6 +137,8 @@ set(JAVA_SOURCE_FILES
${FILAMENT_JAVA_DIR}/com/google/android/filament/VertexBuffer.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/View.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/Viewport.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/proguard/UsedByNative.java
${FILAMENT_JAVA_DIR}/com/google/android/filament/proguard/UsedByReflection.java
# Desktop specific
src/java/com/google/android/filament/DesktopPlatform.java
src/java/com/google/android/filament/FilamentCanvas.java