Merge "Configurable hidden API exemptions."
This commit is contained in:
@@ -32,6 +32,7 @@ import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -157,6 +158,13 @@ public class ZygoteProcess {
|
||||
*/
|
||||
private final Object mLock = new Object();
|
||||
|
||||
/**
|
||||
* List of exemptions to the API blacklist. These are prefix matches on the runtime format
|
||||
* symbol signature. Any matching symbol is treated by the runtime as being on the light grey
|
||||
* list.
|
||||
*/
|
||||
private List<String> mApiBlacklistExemptions = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* The state of the connection to the primary zygote.
|
||||
*/
|
||||
@@ -175,7 +183,7 @@ public class ZygoteProcess {
|
||||
* The process will continue running after this function returns.
|
||||
*
|
||||
* <p>If processes are not enabled, a new thread in the caller's
|
||||
* process is created and main() of <var>processClass</var> called there.
|
||||
* process is created and main() of <var>processclass</var> called there.
|
||||
*
|
||||
* <p>The niceName parameter, if not an empty string, is a custom name to
|
||||
* give to the process instead of using processClass. This allows you to
|
||||
@@ -453,6 +461,49 @@ public class ZygoteProcess {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push hidden API blacklisting exemptions into the zygote process(es).
|
||||
*
|
||||
* <p>The list of exemptions will take affect for all new processes forked from the zygote after
|
||||
* this call.
|
||||
*
|
||||
* @param exemptions List of hidden API exemption prefixes.
|
||||
*/
|
||||
public void setApiBlacklistExemptions(List<String> exemptions) {
|
||||
synchronized (mLock) {
|
||||
mApiBlacklistExemptions = exemptions;
|
||||
maybeSetApiBlacklistExemptions(primaryZygoteState, true);
|
||||
maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
|
||||
if (state == null || state.isClosed()) {
|
||||
return;
|
||||
}
|
||||
if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
state.writer.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
|
||||
state.writer.newLine();
|
||||
state.writer.write("--set-api-blacklist-exemptions");
|
||||
state.writer.newLine();
|
||||
for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
|
||||
state.writer.write(mApiBlacklistExemptions.get(i));
|
||||
state.writer.newLine();
|
||||
}
|
||||
state.writer.flush();
|
||||
int status = state.inputStream.readInt();
|
||||
if (status != 0) {
|
||||
Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to open socket to Zygote process if not already open. If
|
||||
* already open, does nothing. May block and retry. Requires that mLock be held.
|
||||
@@ -467,8 +518,8 @@ public class ZygoteProcess {
|
||||
} catch (IOException ioe) {
|
||||
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
|
||||
}
|
||||
maybeSetApiBlacklistExemptions(primaryZygoteState, false);
|
||||
}
|
||||
|
||||
if (primaryZygoteState.matches(abi)) {
|
||||
return primaryZygoteState;
|
||||
}
|
||||
@@ -480,6 +531,7 @@ public class ZygoteProcess {
|
||||
} catch (IOException ioe) {
|
||||
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
|
||||
}
|
||||
maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
|
||||
}
|
||||
|
||||
if (secondaryZygoteState.matches(abi)) {
|
||||
|
||||
@@ -47,6 +47,8 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
/**
|
||||
@@ -159,6 +161,11 @@ class ZygoteConnection {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (parsedArgs.apiBlacklistExemptions != null) {
|
||||
handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
|
||||
throw new ZygoteSecurityException("Client may not specify capabilities: " +
|
||||
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
|
||||
@@ -278,6 +285,15 @@ class ZygoteConnection {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleApiBlacklistExemptions(String[] exemptions) {
|
||||
try {
|
||||
ZygoteInit.setApiBlacklistExemptions(exemptions);
|
||||
mSocketOutStream.writeInt(0);
|
||||
} catch (IOException ioe) {
|
||||
throw new IllegalStateException("Error writing to command socket", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
protected void preload() {
|
||||
ZygoteInit.lazyPreload();
|
||||
}
|
||||
@@ -423,6 +439,12 @@ class ZygoteConnection {
|
||||
*/
|
||||
boolean startChildZygote;
|
||||
|
||||
/**
|
||||
* Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time,
|
||||
* or when they change, via --set-api-blacklist-exemptions.
|
||||
*/
|
||||
String[] apiBlacklistExemptions;
|
||||
|
||||
/**
|
||||
* Constructs instance and parses args
|
||||
* @param args zygote command-line args
|
||||
@@ -576,6 +598,11 @@ class ZygoteConnection {
|
||||
preloadDefault = true;
|
||||
} else if (arg.equals("--start-child-zygote")) {
|
||||
startChildZygote = true;
|
||||
} else if (arg.equals("--set-api-blacklist-exemptions")) {
|
||||
// consume all remaining args; this is a stand-alone command, never included
|
||||
// with the regular fork command.
|
||||
apiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
|
||||
curArg = args.length;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -590,7 +617,7 @@ class ZygoteConnection {
|
||||
throw new IllegalArgumentException(
|
||||
"Unexpected arguments after --preload-package.");
|
||||
}
|
||||
} else if (!preloadDefault) {
|
||||
} else if (!preloadDefault && apiBlacklistExemptions == null) {
|
||||
if (!seenRuntimeArgs) {
|
||||
throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
|
||||
}
|
||||
|
||||
@@ -514,6 +514,10 @@ public class ZygoteInit {
|
||||
/* should never reach here */
|
||||
}
|
||||
|
||||
public static void setApiBlacklistExemptions(String[] exemptions) {
|
||||
VMRuntime.getRuntime().setHiddenApiExemptions(exemptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PathClassLoader for the given class path that is associated with a shared
|
||||
* namespace, i.e., this classloader can access platform-private native libraries. The
|
||||
|
||||
@@ -2696,13 +2696,15 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates the globla setting "hidden_api_blacklist_exemptions", including tracking the
|
||||
* Encapsulates the global setting "hidden_api_blacklist_exemptions", including tracking the
|
||||
* latest value via a content observer.
|
||||
*/
|
||||
static class HiddenApiBlacklist extends ContentObserver {
|
||||
|
||||
private final Context mContext;
|
||||
private boolean mBlacklistDisabled;
|
||||
private String mExemptionsStr;
|
||||
private List<String> mExemptions = Collections.emptyList();
|
||||
|
||||
public HiddenApiBlacklist(Handler handler, Context context) {
|
||||
super(handler);
|
||||
@@ -2718,8 +2720,22 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
|
||||
private void update() {
|
||||
mBlacklistDisabled = "*".equals(Settings.Global.getString(mContext.getContentResolver(),
|
||||
Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS));
|
||||
String exemptions = Settings.Global.getString(mContext.getContentResolver(),
|
||||
Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS);
|
||||
if (!TextUtils.equals(exemptions, mExemptionsStr)) {
|
||||
mExemptionsStr = exemptions;
|
||||
if ("*".equals(exemptions)) {
|
||||
mBlacklistDisabled = true;
|
||||
mExemptions = Collections.emptyList();
|
||||
} else {
|
||||
mBlacklistDisabled = false;
|
||||
mExemptions = TextUtils.isEmpty(exemptions)
|
||||
? Collections.emptyList()
|
||||
: Arrays.asList(exemptions.split(":"));
|
||||
}
|
||||
zygoteProcess.setApiBlacklistExemptions(mExemptions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
boolean isDisabled() {
|
||||
|
||||
Reference in New Issue
Block a user