android: Manager code for multi platform support.

This commit is contained in:
Joachim Fritzsch 2013-11-17 13:52:37 +01:00
parent f173f76ef5
commit 4479661766
4 changed files with 86 additions and 58 deletions

View File

@ -27,8 +27,13 @@
<string name="auth_file_name" translatable="false">gui_rpc_auth.cfg</string>
<string name="all_projects_list" translatable="false">all_projects_list.xml</string>
<string name="global_prefs_override" translatable="false">global_prefs_override.xml</string>
<string name="assets_dir_arm" translatable="false">armeabi-v7a/</string>
<string name="assets_dir_x86" translatable="false">x86/</string>
<string name="assets_dir_mips" translatable="false">mips/</string>
<!-- BOINC platform -->
<string name="boinc_platform_name" translatable="false">arm-android-linux-gnu</string>
<string name="boinc_platform_name_arm" translatable="false">arm-android-linux-gnu</string>
<string name="boinc_platform_name_x86" translatable="false">x86-android-linux-gnu</string>
<string name="boinc_platform_name_mips" translatable="false">mipsel-android-linux-gnu</string>
<!-- Default preferences of Android app, for BOINC client see assets/global_prefs_override.xml -->
<bool name="prefs_default_autostart">true</bool>
<bool name="prefs_default_notifications">true</bool>

View File

@ -42,8 +42,8 @@
<string name="attachproject_login_header_home">Home:</string>
<string name="attachproject_login_header_url">Website:</string>
<string name="attachproject_login_header_platform">Android:</string>
<string name="attachproject_login_platform_supported">This project supports Android devices</string>
<string name="attachproject_login_platform_not_supported">This project does not support Android devices</string>
<string name="attachproject_login_platform_supported">Device type is supported by this project</string>
<string name="attachproject_login_platform_not_supported">Device is not supported by this project</string>
<string name="attachproject_login_category_terms_of_use">Terms of use for</string>
<string name="attachproject_login_accept_terms_of_use">By creating an account with this project, you accept the terms of use as shown above.</string>
<string name="attachproject_login_category_login">Sign in with existing account</string>

View File

@ -371,7 +371,8 @@ public class AttachProjectLoginActivity extends Activity{
private Boolean platformSupported() {
if(projectConfig == null) return false;
String platformName = getString(R.string.boinc_platform_name);
if(!mIsBound) return false;
String platformName = getString(monitor.getBoincPlatform());
Boolean supported = false;
for(PlatformInfo platform: projectConfig.platforms) {
if(platform.name.equals(platformName)) {

View File

@ -34,16 +34,15 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import android.app.NotificationManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
@ -82,7 +81,6 @@ public class Monitor extends Service {
private String clientConfig;
private String authFileName;
private String allProjectsList;
private String globalOverridePreferences;
private String clientPath;
private Integer clientStatusInterval;
private Integer deviceStatusIntervalScreenOff;
@ -120,10 +118,10 @@ public class Monitor extends Service {
status.setSetupStatus(ClientStatus.SETUP_STATUS_LAUNCHING,true);
String clientProcessName = clientPath + clientName;
String md5AssetClient = ComputeMD5Asset(clientName);
String md5AssetClient = computeMd5(clientName, true);
//if(Logging.DEBUG) Log.d(Logging.TAG, "Hash of client (Asset): '" + md5AssetClient + "'");
String md5InstalledClient = ComputeMD5File(clientProcessName);
String md5InstalledClient = computeMd5(clientProcessName, false);
//if(Logging.DEBUG) Log.d(Logging.TAG, "Hash of client (File): '" + md5InstalledClient + "'");
// If client hashes do not match, we need to install the one that is a part
@ -264,13 +262,20 @@ public class Monitor extends Service {
return true;
}
// Copies file from APK's assets directory to internal storage
private Boolean installFile(String file, Boolean override, Boolean executable) {
Boolean success = false;
byte[] b = new byte [1024];
int count;
// If file is executable, cpu architecture has to be evaluated
// and assets directory select accordingly
String source = "";
if(executable) source = getAssestsDirForCpuArchitecture() + file;
else source = file;
try {
if(Logging.DEBUG) Log.d(Logging.TAG, "installing: " + file);
if(Logging.DEBUG) Log.d(Logging.TAG, "installing: " + source);
File target = new File(clientPath + file);
@ -290,7 +295,7 @@ public class Monitor extends Service {
}
// Copy file from the asset manager to clientPath
InputStream asset = getApplicationContext().getAssets().open(file);
InputStream asset = getApplicationContext().getAssets().open(source);
OutputStream targetData = new FileOutputStream(target);
while((count = asset.read(b)) != -1){
targetData.write(b, 0, count);
@ -309,15 +314,55 @@ public class Monitor extends Service {
success = isExecutable; // return false, if not executable
}
if(Logging.DEBUG) Log.d(Logging.TAG, "install of " + file + " successfull. executable: " + executable + "/" + isExecutable);
if(Logging.DEBUG) Log.d(Logging.TAG, "install of " + source + " successfull. executable: " + executable + "/" + isExecutable);
} catch (IOException e) {
if(Logging.ERROR) Log.e(Logging.TAG, "IOException: " + e.getMessage());
if(Logging.DEBUG) Log.d(Logging.TAG, "install of " + file + " failed.");
if(Logging.DEBUG) Log.d(Logging.TAG, "install of " + source + " failed.");
}
return success;
}
// correct directory of binaries in assets directory depends on
// the cpu architecture of the device: arm, x86 or mips
// this function returns the directory to the right assets directory
// defaults to ARM
private String getAssestsDirForCpuArchitecture() {
String archAssetsDirectory="";
switch(getBoincPlatform()) {
case R.string.boinc_platform_name_arm:
archAssetsDirectory = getString(R.string.assets_dir_arm);
break;
case R.string.boinc_platform_name_x86:
archAssetsDirectory = getString(R.string.assets_dir_x86);
break;
case R.string.boinc_platform_name_mips:
archAssetsDirectory = getString(R.string.assets_dir_mips);
break;
}
return archAssetsDirectory;
}
// returns the id of the BOINC platform string, depending on the device's
// cpu architecture.
// i.e. arm, x86 or mips
// defaults to ARM
public int getBoincPlatform() {
int platformId = 0;
String arch = System.getProperty("os.arch");
String normalizedArch = arch.substring(0, 4).toUpperCase(Locale.US);
if(normalizedArch.contains("ARM")) platformId = R.string.boinc_platform_name_arm;
else if (normalizedArch.contains("MIPS")) platformId = R.string.boinc_platform_name_mips;
else if (normalizedArch.contains("86")) platformId= R.string.boinc_platform_name_x86;
else {
if(Logging.WARNING) Log.w(Logging.TAG,"could not map os.arch (" + arch + ") to platform, default to arm.");
platformId = R.string.boinc_platform_name_arm;
}
if(Logging.DEBUG) Log.d(Logging.TAG,"BOINC platform: " + getString(platformId) + " for os.arch: " + arch);
return platformId;
}
// Connects to running BOINC client.
//
@ -339,16 +384,20 @@ public class Monitor extends Service {
private void updateStatus(){
// check whether RPC client connection is alive
if(!rpc.connectionAlive()) {
clientSetup(); // start setup routine
reportDeviceStatus();
readClientStatus(true); // read initial data
if(clientSetup()) { // start setup routine
// interact with client only if connection established successfully
reportDeviceStatus();
readClientStatus(true); // read initial data
}
}
if(!screenOn && screenOffStatusOmitCounter < deviceStatusIntervalScreenOff) screenOffStatusOmitCounter++; // omit status reporting according to configuration
else {
// screen is on, or omit counter reached limit
reportDeviceStatus();
readClientStatus(false); // readClientStatus is also required when screen is off, otherwise no wakeLock acquisition.
if(rpc.connectionAlive()) {
reportDeviceStatus();
readClientStatus(false); // readClientStatus is also required when screen is off, otherwise no wakeLock acquisition.
}
}
}
@ -425,53 +474,25 @@ public class Monitor extends Service {
if(Logging.ERROR) Log.e(Logging.TAG, "Monitor.reportDeviceStatus excpetion: " + e.getMessage());
}
}
// Compute MD5 of the requested asset
//
private String ComputeMD5Asset(String file) {
byte[] b = new byte [1024];
int count;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
InputStream asset = getApplicationContext().getAssets().open(file);
while((count = asset.read(b)) != -1){
md5.update(b, 0, count);
}
asset.close();
byte[] md5hash = md5.digest();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < md5hash.length; ++i) {
sb.append(String.format("%02x", md5hash[i]));
}
return sb.toString();
} catch (IOException e) {
if(Logging.ERROR) Log.e(Logging.TAG, "IOException: " + e.getMessage());
} catch (NoSuchAlgorithmException e) {
if(Logging.ERROR) Log.e(Logging.TAG, "NoSuchAlgorithmException: " + e.getMessage());
}
return "";
}
// Compute MD5 of the requested file
//
private String ComputeMD5File(String file) {
// if inAssets is true, tries to locate file in assets directory,
// if not, it tries to locate in internal storage of application
private String computeMd5(String fileName, Boolean inAssets) {
byte[] b = new byte [1024];
int count;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
File target = new File(file);
InputStream asset = new FileInputStream(target);
while((count = asset.read(b)) != -1){
InputStream fs = null;
if(inAssets) fs = getApplicationContext().getAssets().open(getAssestsDirForCpuArchitecture() + fileName);
else fs = new FileInputStream(new File(fileName));
while((count = fs.read(b)) != -1){
md5.update(b, 0, count);
}
asset.close();
fs.close();
byte[] md5hash = md5.digest();
StringBuilder sb = new StringBuilder();
@ -617,10 +638,12 @@ public class Monitor extends Service {
if(allProjects == null) return;
String platform = getString(getBoincPlatform());
if(Logging.DEBUG) Log.d(Logging.TAG, "readAndroidProjectsList for platform: " + platform);
//filter projects that do not support Android
for (ProjectInfo project: allProjects) {
if(project.platforms.contains(getString(R.string.boinc_platform_name))) {
if(Logging.DEBUG) Log.d(Logging.TAG, project.name + " supports " + getString(R.string.boinc_platform_name));
if(project.platforms.contains(platform)) {
androidProjects.add(project);
}
}
@ -680,7 +703,6 @@ public class Monitor extends Service {
clientConfig = getString(R.string.client_config);
authFileName = getString(R.string.auth_file_name);
allProjectsList = getString(R.string.all_projects_list);
globalOverridePreferences = getString(R.string.global_prefs_override);
clientStatusInterval = getResources().getInteger(R.integer.status_update_interval_ms);
deviceStatusIntervalScreenOff = getResources().getInteger(R.integer.device_status_update_screen_off_every_X_loop);