3 * Setting up the Android environment
5 * (c) 2018 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the Trivial IP Encryption (TrIPE) Android app.
12 * TrIPE is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
17 * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
26 package uk.org.distorted.tripe; package object app {
28 /*----- Imports -----------------------------------------------------------*/
30 import java.io.{File, IOException};
32 import scala.collection.mutable.HashMap;
34 import android.content.Context; import Context.MODE_WORLD_READABLE;
35 import android.os.Build; import Build.{CPU_ABI, CPU_ABI2};
36 import android.util.Log;
38 import sys.FileImplicits._;
40 /*----- Regular expressions for parsing the `.installed file --------------*/
42 private final val RX_COMMENT = """(?x) ^ \s* (?: \# .* )? $""".r;
43 private final val RX_KEYVAL = """(?x) ^ \s*
49 /*----- Main code ---------------------------------------------------------*/
51 private final val TAG = "TrIPE";
53 var root: File = null;
55 private def install(ctx: Context, inst: HashMap[String, String]) {
57 /* First, figure out which ABIs are wanted on this device. Unfortunately,
58 * the good way of doing this isn't available in our minimum API level, so
59 * we must use reflection.
62 classOf[Build].getField("SUPPORTED_ABIS").get(null).
63 asInstanceOf[Array[String]]
64 } catch { case _: NoSuchFieldException =>
65 Array(CPU_ABI, CPU_ABI2) flatMap {
66 case null | "" => None
70 Log.d(TAG, s"abis = ${abis.mkString(", ")}");
72 /* Clear out whatever might be there already. */
73 val bindir = root/"bin";
77 /* Now extract each of our binaries using the best available ABI. */
78 val assets = ctx.getAssets;
80 val binsrc = s"bin/$abi";
81 for (base <- assets.list(binsrc)) {
82 val outfile = bindir/base;
83 if (!outfile.exists_!) {
84 Log.d(TAG, s"install: extract `$base' using abi `$abi'");
85 outfile.withOutput { out =>
86 closing(assets.open(s"$binsrc/$base")) { in =>
87 for ((buf, n) <- blocks(in)) out.write(buf, 0, n);
91 outfile.chmod_!(0x1ed);
95 /* Write out a new install file. */
96 val infofile = root/".installed";
97 val newinfofile = root/".installed.new";
98 newinfofile.withWriter { out =>
99 out.write(s"""### -*-conf-*-
101 uuid = ${ctx.getString(R.string.auto_build_uuid)}
104 newinfofile.rename_!(infofile);
107 def setup(ctx: Context) {
109 /* Make our root directory and remember where it is. */
110 root = ctx.getFilesDir;
112 throw new IOException("system failed to create `files' " +
113 "(but didn't tell us)");
116 /* Find out which build, if any, corresponds to what's there already. */
117 val inst = HashMap[String, String]();
118 try { root/".installed" withReader { in =>
120 for (line <- lines(in)) {
122 case RX_COMMENT() => ok;
123 case RX_KEYVAL(k, v) => inst(k) = v;
124 case _ => Log.w(TAG, s".installed:$lno: ignored unparseable line");
129 case e: IOException =>
130 Log.w(TAG, s".installed: I/O error: ${e.getMessage}");
133 /* If this doesn't match, then we have some work to do. */
134 if (inst.getOrElse("uuid", "<nothing>") !=
135 ctx.getString(R.string.auto_build_uuid))
139 /*----- That's all, folks -------------------------------------------------*/