First commit of split-select tool
This tool emits a set of rules as JSON for when a Split APK
should match a target device.
Change-Id: I8bfbdfbdb51efcfc645889dd03e1961f16e39645
diff --git a/tools/split-select/Rule.cpp b/tools/split-select/Rule.cpp
new file mode 100644
index 0000000..9559fe2
--- /dev/null
+++ b/tools/split-select/Rule.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "Rule.h"
+
+#include <utils/String8.h>
+
+using namespace android;
+
+namespace split {
+
+inline static void indentStr(String8& str, int indent) {
+ while (indent > 0) {
+ str.append(" ");
+ indent--;
+ }
+}
+
+String8 Rule::toJson(int indent) const {
+ String8 str;
+ indentStr(str, indent);
+ str.append("{\n");
+ indent++;
+ indentStr(str, indent);
+ str.append("\"op\": \"");
+ switch (op) {
+ case ALWAYS_TRUE:
+ str.append("ALWAYS_TRUE");
+ break;
+ case GREATER_THAN:
+ str.append("GREATER_THAN");
+ break;
+ case LESS_THAN:
+ str.append("LESS_THAN");
+ break;
+ case EQUALS:
+ str.append("EQUALS");
+ break;
+ case AND_SUBRULES:
+ str.append("AND_SUBRULES");
+ break;
+ case OR_SUBRULES:
+ str.append("OR_SUBRULES");
+ break;
+ case CONTAINS_ANY:
+ str.append("CONTAINS_ANY");
+ break;
+ default:
+ str.appendFormat("%d", op);
+ break;
+ }
+ str.append("\"");
+
+ if (negate) {
+ str.append(",\n");
+ indentStr(str, indent);
+ str.append("\"negate\": true");
+ }
+
+ bool includeKey = true;
+ switch (op) {
+ case AND_SUBRULES:
+ case OR_SUBRULES:
+ includeKey = false;
+ break;
+ default:
+ break;
+ }
+
+ if (includeKey) {
+ str.append(",\n");
+ indentStr(str, indent);
+ str.append("\"property\": \"");
+ switch (key) {
+ case NONE:
+ str.append("NONE");
+ break;
+ case SDK_VERSION:
+ str.append("SDK_VERSION");
+ break;
+ case SCREEN_DENSITY:
+ str.append("SCREEN_DENSITY");
+ break;
+ case NATIVE_PLATFORM:
+ str.append("NATIVE_PLATFORM");
+ break;
+ case LANGUAGE:
+ str.append("LANGUAGE");
+ break;
+ default:
+ str.appendFormat("%d", key);
+ break;
+ }
+ str.append("\"");
+ }
+
+ if (op == AND_SUBRULES || op == OR_SUBRULES) {
+ str.append(",\n");
+ indentStr(str, indent);
+ str.append("\"subrules\": [\n");
+ const size_t subruleCount = subrules.size();
+ for (size_t i = 0; i < subruleCount; i++) {
+ str.append(subrules[i]->toJson(indent + 1));
+ if (i != subruleCount - 1) {
+ str.append(",");
+ }
+ str.append("\n");
+ }
+ indentStr(str, indent);
+ str.append("]");
+ } else {
+ switch (key) {
+ case SDK_VERSION:
+ case SCREEN_DENSITY: {
+ str.append(",\n");
+ indentStr(str, indent);
+ str.append("\"args\": [");
+ const size_t argCount = longArgs.size();
+ for (size_t i = 0; i < argCount; i++) {
+ if (i != 0) {
+ str.append(", ");
+ }
+ str.appendFormat("%d", longArgs[i]);
+ }
+ str.append("]");
+ break;
+ }
+ case LANGUAGE:
+ case NATIVE_PLATFORM: {
+ str.append(",\n");
+ indentStr(str, indent);
+ str.append("\"args\": [");
+ const size_t argCount = stringArgs.size();
+ for (size_t i = 0; i < argCount; i++) {
+ if (i != 0) {
+ str.append(", ");
+ }
+ str.append(stringArgs[i]);
+ }
+ str.append("]");
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ str.append("\n");
+ indent--;
+ indentStr(str, indent);
+ str.append("}");
+ return str;
+}
+
+sp<Rule> Rule::simplify(sp<Rule> rule) {
+ if (rule->op != AND_SUBRULES && rule->op != OR_SUBRULES) {
+ return rule;
+ }
+
+ Vector<sp<Rule> > newSubrules;
+ newSubrules.setCapacity(rule->subrules.size());
+ const size_t subruleCount = rule->subrules.size();
+ for (size_t i = 0; i < subruleCount; i++) {
+ sp<Rule> simplifiedRule = simplify(rule->subrules.editItemAt(i));
+ if (simplifiedRule != NULL) {
+ if (simplifiedRule->op == rule->op) {
+ newSubrules.appendVector(simplifiedRule->subrules);
+ } else {
+ newSubrules.add(simplifiedRule);
+ }
+ }
+ }
+
+ const size_t newSubruleCount = newSubrules.size();
+ if (newSubruleCount == 0) {
+ return NULL;
+ } else if (subruleCount == 1) {
+ return newSubrules.editTop();
+ }
+ rule->subrules = newSubrules;
+ return rule;
+}
+
+} // namespace split