Verified Commit 1701f7a5 authored by Andreas Redmer's avatar Andreas Redmer 👍

stash - no idea

parent 132e2b4d
Pipeline #44466753 (#291) passed with stages
in 3 minutes and 56 seconds
......@@ -57,13 +57,13 @@ public class AppDownloader {
final Installer installer = Util.getAppInstaller(context);
String url = repoBaseUrl+mApp.apkname;
final String file = getAbsoluteFilenameOfDownloadTarget(context, mApp);
final String filename = getAbsoluteFilenameOfDownloadTarget(context, mApp);
final MutableExtras extras = new MutableExtras();
extras.putString("id", mApp.id);
final Request request = new Request(url, file);
final Request request = new Request(url, filename);
request.setPriority(Priority.HIGH);
request.setNetworkType(NetworkType.ALL);
request.setExtras(extras);
......@@ -121,15 +121,15 @@ public class AppDownloader {
}
}
};
Log.d(TAG, "done");
// TODO check correct targe file name here
Log.d(TAG, "finished downloading "+filename);
String appId = download.getExtras().getString("id","");
AppDatabase db = AppDatabase.get(context);
ApplicationBean ab = db.appDao().getApplicationBean(appId);
db.close();
final String fn = getAbsoluteFilenameOfDownloadTarget(context, ab);
if (install)
installer.installApp(context, file, onComplete);
installer.installApp(context, filename, onComplete);
}
@Override
......
......@@ -54,7 +54,7 @@ public class AuthorListActivity extends AppCompatActivity {
AppDatabase db = AppDatabase.get(getApplicationContext());
final AuthorBean[] allAuthors = db.appDao().getAllAuthors();
db.close();
final AuthorArrayAdapter adapter = new AuthorArrayAdapter(this, allAuthors);
authorsList.setAdapter(adapter);
......
......@@ -216,7 +216,7 @@ public class MainActivity extends AppCompatActivity
AsyncTask.execute(new Runnable() {
@Override
public void run() {
Util.waitForAllDownloadsToFinish(activity);
// Util.waitForAllDownloadsToFinish(activity);
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
......@@ -358,22 +358,22 @@ public class MainActivity extends AppCompatActivity
appCollectionDescriptorList.clear();
AppDatabase db = AppDatabase.get(context);
final String[] categoryNames = db.appDao().getAllCategoryNames();
db.close();
for (String cn : categoryNames) {
AppCollectionDescriptor ad = new AppCollectionDescriptor(context, "cat:" + cn);
appCollectionDescriptorList.add(ad);
Collections.sort(appCollectionDescriptorList);
}
db.close();
} else if (screen.equals("tags")) {
appCollectionDescriptorList.clear();
AppDatabase db = AppDatabase.get(context);
final String[] tagNames = db.appDao().getAllTagNames();
db.close();
for (String tn : tagNames) {
AppCollectionDescriptor ad = new AppCollectionDescriptor(context, "tag:" + tn);
appCollectionDescriptorList.add(ad);
Collections.sort(appCollectionDescriptorList);
}
db.close();
}
runOnUiThread(new Runnable() {
......
......@@ -129,31 +129,33 @@ public class AutoRootAppInstallTask extends AsyncTask<Void, ApplicationBean, Voi
}
public void installApps() {
for(ApplicationBean packageInfo: packages){
private void installApps() {
for(ApplicationBean ab: packages){
current++;
publishProgress(packageInfo);
publishProgress(ab);
try {
if (Util.isRooted()) {
final String downloadTarget = AppDownloader.getAbsoluteFilenameOfDownloadTarget(context, packageInfo);
installApp(downloadTarget);
installApp(ab);
}
}catch (Exception e) {
}
catch (Exception e) {
e.printStackTrace();
}
}
}
public void installApp(String filename) {
Util.waitForAllDownloadsToFinish(context);
private void installApp(ApplicationBean ab) {
// Util.waitForAllDownloadsToFinish(context);
//TODO use RootInstaller here
File file = new File(filename);
Util.waitForFileToBeStable(file);
if(file.exists()){
final boolean downloadIsCool = Util.waitForAppDownloadToBeCorrectlyFinished(context, ab);
final String downloadTarget = AppDownloader.getAbsoluteFilenameOfDownloadTarget(context, ab);
// File file = new File(filename);
// Util.waitForFileToBeStable(file);
if(downloadIsCool){
try {
String command;
command = "pm install -r " + filename;
command = "pm install -r " + downloadTarget;
Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
proc.waitFor();
if(proc.exitValue() != 0) {
......
......@@ -90,7 +90,7 @@ public class BariaInstaller {
// wait for each file to be completely downloaded
for (String fn:apks) {
File f = new File (fn);
Util.waitForFileToBeStable(f);
// Util.waitForFileToBeStable(f); // TODO HERE
}
//then do the installations
((Activity)context).runOnUiThread(new Runnable() {
......
......@@ -115,6 +115,7 @@ class AppBeanJsonParser extends AbstractJsonParser implements JsonParser{
ab.marketversion = latestPackage.getString("versionName");
ab.marketvercode = latestPackage.getString("versionCode");
ab.hash = latestPackage.getString("hash");
// permissions from packages (optional)
final JSONArray permissionsArray = latestPackage.optJSONArray("uses-permission");
......
......@@ -126,8 +126,6 @@ public class DownloadJaredJsonTask extends AsyncTask<String, Void, List<Applicat
}
}
db.appDao().insertTags(allTagMappings);
db.close();
// update the UI after DB has been updated (on the first 2 tabs)
......
/*
* Copyright (C) 2019 Andreas Redmer <ar-gdroid@abga.be>
* Copyright (C) 2010-2011 Ciaran Gultnieks <ciaran@ciarang.com>
* Copyright (C) 2011 Henrik Tunedal <tunedal@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
package org.gdroid.gdroid.util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.util.Locale;
public class Hasher {
private MessageDigest digest;
private File file;
private byte[] array;
private String hashCache;
public Hasher(String type, File f) throws NoSuchAlgorithmException {
init(type);
this.file = f;
}
public Hasher(String type, byte[] a) throws NoSuchAlgorithmException {
init(type);
this.array = a;
}
private void init(String type) throws NoSuchAlgorithmException {
try {
digest = MessageDigest.getInstance(type);
} catch (Exception e) {
throw new NoSuchAlgorithmException(e);
}
}
// Calculate hash (as lowercase hexadecimal string) for the file
// specified in the constructor. This will return a cached value
// on subsequent invocations. Returns the empty string on failure.
public String getHash() {
if (hashCache != null) {
return hashCache;
}
if (file != null) {
byte[] buffer = new byte[1024];
int read;
InputStream input = null;
try {
input = new BufferedInputStream(new FileInputStream(file));
while ((read = input.read(buffer)) > 0) {
digest.update(buffer, 0, read);
}
} catch (Exception e) {
hashCache = "";
return hashCache;
} finally {
Util.closeQuietly(input);
}
} else {
digest.update(array);
}
hashCache = hex(digest.digest());
return hashCache;
}
// Compare the calculated hash to another string, ignoring case,
// returning true if they are equal. The empty string and null are
// considered non-matching.
public boolean match(String otherHash) {
if (otherHash == null) {
return false;
}
if (hashCache == null) {
getHash();
}
return hashCache.equals(otherHash.toLowerCase(Locale.ENGLISH));
}
/**
* Checks the file against the provided hash, returning whether it is a match.
*/
public static boolean isFileMatchingHash(File file, String hash, String hashType) {
if (!file.exists()) {
return false;
}
try {
Hasher hasher = new Hasher(hashType, file);
return hasher.match(hash);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public static String hex(Certificate cert) {
byte[] encoded;
try {
encoded = cert.getEncoded();
} catch (CertificateEncodingException e) {
encoded = new byte[0];
}
return hex(encoded);
}
private static String hex(byte[] sig) {
byte[] csig = new byte[sig.length * 2];
for (int j = 0; j < sig.length; j++) {
byte v = sig[j];
int d = (v >> 4) & 0xf;
csig[j * 2] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
d = v & 0xf;
csig[j * 2 + 1] = (byte) (d >= 10 ? ('a' + d - 10) : ('0' + d));
}
return new String(csig);
}
public static byte[] unhex(String data) {
byte[] rawdata = new byte[data.length() / 2];
for (int i = 0; i < data.length(); i++) {
char halfbyte = data.charAt(i);
int value;
if ('0' <= halfbyte && halfbyte <= '9') {
value = halfbyte - '0';
} else if ('a' <= halfbyte && halfbyte <= 'f') {
value = halfbyte - 'a' + 10;
} else if ('A' <= halfbyte && halfbyte <= 'F') {
value = halfbyte - 'A' + 10;
} else {
throw new IllegalArgumentException("Bad hex digit");
}
rawdata[i / 2] += (byte) (i % 2 == 0 ? value << 4 : value);
}
return rawdata;
}
}
......@@ -42,7 +42,10 @@ import org.gdroid.gdroid.installer.DefaultInstaller;
import org.gdroid.gdroid.installer.Installer;
import org.gdroid.gdroid.installer.RootInstaller;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
......@@ -150,6 +153,7 @@ public class Util {
final ApplicationBean app = db.appDao().getApplicationBean(starredAppId);
ret.add(app);
}
db.close();
Collections.sort(ret, new AppBeanNameComparator(context,
Util.getOrderByColumn(context), Util.getOrderByDirection(context).equals("ASC")));
return ret;
......@@ -200,13 +204,14 @@ public class Util {
final PackageManager pm = context.getPackageManager();
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
List<String> packageNames = new ArrayList<>(packages.size());
AppDatabase db = AppDatabase.get(context);
for (ApplicationInfo packageInfo : packages) {
packageNames.add(packageInfo.packageName);
}
AppDatabase db = AppDatabase.get(context);
// List<ApplicationBean> ret = db.appDao().getSomeApplicationBeans2(packageNames, getOrderByColumn(context));
List<ApplicationBean> ret = db.appDao().getSomeApplicationBeansList(packageNames);
db.close();
Collections.sort(ret, new AppBeanNameComparator(context,
Util.getOrderByColumn(context),
Util.getOrderByDirection(context).equals("ASC"),
......@@ -550,17 +555,44 @@ public class Util {
AppDownloader.getFetch(context).awaitFinishOrTimeout(120000L);
}
public static void waitForFileToBeStable(File file) {
public static boolean waitForAppDownloadToBeCorrectlyFinished(Context context, ApplicationBean ab)
{
final String downloadTarget = AppDownloader.getAbsoluteFilenameOfDownloadTarget(context, ab);
File file = new File(downloadTarget);
waitForFileToBeStable(file);
if (!Hasher.isFileMatchingHash(file, ab.hash , "sha256"))
{
try {
Hasher h = new Hasher("sha256", file);
Log.e(TAG, String.format("FileHash mismatch expected %s but was %s for file %s ", ab.hash, h.getHash(), downloadTarget));
} catch (NoSuchAlgorithmException e) {
//e.printStackTrace();
Log.e(TAG,"exception in error handling", e);
}
return false;
}
Log.i(TAG,String.format("Download of file %s completed with correct hash", downloadTarget));
return true;
}
private static void waitForFileToBeStable(File file) {
long fileSize = file.length();
int waitCount = 0;
while (true)
{
Log.d(TAG, "waiting for download "+file.getName()+" to settle. Got now "+fileSize+" bytes");
try {
Thread.sleep(5000);
waitCount++;
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long newFileSize = file.length();
if (waitCount >= 30 && newFileSize == 0L)
{
Log.w(TAG, "download of "+file.getName()+" did not start ");
break;
}
if (newFileSize == 0L)
continue;
if (newFileSize == fileSize)
......@@ -569,6 +601,16 @@ public class Util {
}
}
public static void closeQuietly(Closeable closeable) {
if (closeable == null) {
return;
}
try {
closeable.close();
} catch (IOException ioe) {
// ignore
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment