Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb7caa96 authored by Martijn Coenen's avatar Martijn Coenen
Browse files

Allow app to specify class name for app zygote preloading.

Instead of using a fixed class name, define an interface for
preloading application code that must be implemented by applications
that use the application zygote.

Also, add an ApplicationInfo parameter to said function, so the app
knows where to look for its data and code.

Bug: 111434506
Test: atest CtsApptestCases:ServiceTest
      atest CtsSeccompHostTestCases

Change-Id: I1f8472da89dc90562dcb4e479e3d87ebf49b926c
parent 4b988166
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1622,6 +1622,7 @@ package android {
    field @Deprecated public static final int yearListSelectorColor = 16843930; // 0x101049a
    field public static final int yesNoPreferenceStyle = 16842896; // 0x1010090
    field public static final int zAdjustment = 16843201; // 0x10101c1
    field public static final int zygotePreloadName = 16844195; // 0x10105a3
  }
  public static final class R.bool {
@@ -6477,6 +6478,10 @@ package android.app {
    method public void onColorsChanged(android.app.WallpaperColors, int);
  }
  public interface ZygotePreload {
    method public void doPreload(android.content.pm.ApplicationInfo);
  }
}
package android.app.admin {
+42 −0
Original line number Diff line number Diff line
/*
 * 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 android.app;

import android.content.pm.ApplicationInfo;

/**
 * This is the interface to be implemented for the class that is specified by the
 * {@link android.R.styleable#AndroidManifestApplication_zygotePreloadName
 * android:zygotePreloadName} of the <application> tag.
 *
 * It is responsible for preloading application code and data, that will be shared by all
 * isolated services that have the
 * {@link android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} attribute
 * of the &lt;service&gt; tag set to <code>true</code>.
 *
 * Note that this implementations of this class must provide a default constructor with no
 * arguments.
 */
public interface ZygotePreload {
    /**
     * This method is called once every time the Application Zygote is started. It is normally
     * started the first time an isolated service that uses it is started. The Application Zygote
     * will be stopped when all isolated services that use it are stopped.
     *
     * @param appInfo The ApplicationInfo object belonging to the application
     */
    void doPreload(ApplicationInfo appInfo);
}
+6 −0
Original line number Diff line number Diff line
@@ -1192,6 +1192,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
    /** @hide */
    public boolean hiddenUntilInstalled;

    /** @hide */
    public String zygotePreloadName;

    /**
     * Represents the default policy. The actual policy used will depend on other properties of
     * the application, e.g. the target SDK version.
@@ -1533,6 +1536,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        compileSdkVersionCodename = orig.compileSdkVersionCodename;
        mHiddenApiPolicy = orig.mHiddenApiPolicy;
        hiddenUntilInstalled = orig.hiddenUntilInstalled;
        zygotePreloadName = orig.zygotePreloadName;
    }

    public String toString() {
@@ -1609,6 +1613,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        dest.writeString(appComponentFactory);
        dest.writeInt(mHiddenApiPolicy);
        dest.writeInt(hiddenUntilInstalled ? 1 : 0);
        dest.writeString(zygotePreloadName);
    }

    public static final Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1682,6 +1687,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
        appComponentFactory = source.readString();
        mHiddenApiPolicy = source.readInt();
        hiddenUntilInstalled = source.readInt() != 0;
        zygotePreloadName = source.readString();
    }

    /**
+3 −0
Original line number Diff line number Diff line
@@ -3907,6 +3907,9 @@ public class PackageParser {
            outError[0] = "Invalid class loader name: " + ai.classLoaderName;
        }

        ai.zygotePreloadName = sa.getString(
                com.android.internal.R.styleable.AndroidManifestApplication_zygotePreloadName);

        sa.recycle();

        if (outError[0] != null) {
+25 −14
Original line number Diff line number Diff line
@@ -17,13 +17,15 @@
package com.android.internal.os;

import android.app.LoadedApk;
import android.app.ZygotePreload;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.net.LocalSocket;
import android.util.Log;

import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
@@ -76,20 +78,29 @@ class AppZygoteInit {

            Zygote.allowAppFilesAcrossFork(appInfo);

            if (appInfo.zygotePreloadName != null) {
                Class<?> cl;
                Method m;
                try {
                cl = Class.forName(appInfo.packageName + ".ZygotePreload", true, loader);
                m = cl.getMethod("doPreload");
                m.setAccessible(true);
                m.invoke(null);
            } catch (ClassNotFoundException e) {
                // Don't treat this as an error since an app may not want to do any preloads
                Log.w(TAG, "No ZygotePreload class found for " + appInfo.packageName);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                    ComponentName preloadName = ComponentName.createRelative(appInfo.packageName,
                            appInfo.zygotePreloadName);
                    cl = Class.forName(preloadName.getClassName(), true, loader);
                    if (!ZygotePreload.class.isAssignableFrom(cl)) {
                        Log.e(TAG, preloadName.getClassName() + " does not implement "
                                + ZygotePreload.class.getName());
                    } else {
                        Constructor<?> ctor = cl.getConstructor();
                        ZygotePreload preloadObject = (ZygotePreload) ctor.newInstance();
                        preloadObject.doPreload(appInfo);
                    }
                } catch (ReflectiveOperationException e) {
                    Log.e(TAG, "AppZygote application preload failed for "
                        + appInfo.packageName, e);
                            + appInfo.zygotePreloadName, e);
                }
            } else {
                Log.i(TAG, "No zygotePreloadName attribute specified.");
            }

            try {
                DataOutputStream socketOut = getSocketOutputStream();
                socketOut.writeInt(loader != null ? 1 : 0);
Loading