From 80d8c5953efde1a579f67812a7403aefd418af87 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 27 Feb 2015 01:16:06 -0500 Subject: [PATCH] Rewrite the app art caching and fetching (again!) to finally address OOM problems and speed up art loading --- app/build.gradle | 4 - app/libs/limelight-common.jar | Bin 952898 -> 953008 bytes .../com/limelight/grid/AppGridAdapter.java | 31 +++++- .../grid/assets/CachedAppAssetLoader.java | 64 +++++++----- .../grid/assets/DiskAssetLoader.java | 15 ++- .../grid/assets/MemoryAssetLoader.java | 6 +- .../grid/assets/NetworkAssetLoader.java | 97 +++--------------- .../java/com/limelight/utils/CacheHelper.java | 9 ++ 8 files changed, 98 insertions(+), 128 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index bff822c5..7eb77625 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -67,10 +67,6 @@ dependencies { compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.51' compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.51' - compile group: 'com.google.android', name: 'support-v4', version:'r7' - compile group: 'com.koushikdutta.ion', name: 'ion', version:'2.0.5' - compile group: 'com.google.code.gson', name: 'gson', version:'2.3.1' - compile group: 'com.squareup.okhttp', name: 'okhttp', version:'2.2.0' compile group: 'com.squareup.okio', name:'okio', version:'1.2.0' diff --git a/app/libs/limelight-common.jar b/app/libs/limelight-common.jar index 47febbf9117b0bcb547baccff8d69d641a9007bb..2bffce0616c1c3c0363d09f9ecfb5ddc58d36496 100644 GIT binary patch delta 10222 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

#^)s)q>*CodPo0>CQ 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 diff --git a/app/src/main/java/com/limelight/grid/AppGridAdapter.java b/app/src/main/java/com/limelight/grid/AppGridAdapter.java index b4e87227..6a87fba6 100644 --- a/app/src/main/java/com/limelight/grid/AppGridAdapter.java +++ b/app/src/main/java/com/limelight/grid/AppGridAdapter.java @@ -2,10 +2,12 @@ package com.limelight.grid; import android.app.Activity; import android.graphics.Bitmap; +import android.util.DisplayMetrics; import android.widget.ImageView; import android.widget.TextView; import com.limelight.AppView; +import com.limelight.LimeLog; import com.limelight.R; import com.limelight.grid.assets.CachedAppAssetLoader; import com.limelight.grid.assets.DiskAssetLoader; @@ -26,6 +28,10 @@ import java.util.concurrent.ConcurrentHashMap; public class AppGridAdapter extends GenericGridAdapter { private final Activity activity; + private static final int ART_WIDTH_PX = 300; + private static final int SMALL_WIDTH_DP = 100; + private static final int LARGE_WIDTH_DP = 150; + private final CachedAppAssetLoader loader; private final ConcurrentHashMap, CachedAppAssetLoader.LoaderTuple> loadingTuples = new ConcurrentHashMap<>(); private final ConcurrentHashMap backgroundLoadingTuples = new ConcurrentHashMap<>(); @@ -33,8 +39,26 @@ public class AppGridAdapter extends GenericGridAdapter { public AppGridAdapter(Activity activity, boolean listMode, boolean small, ComputerDetails computer, String uniqueId) throws KeyManagementException, NoSuchAlgorithmException { super(activity, listMode ? R.layout.simple_row : (small ? R.layout.app_grid_item_small : R.layout.app_grid_item), R.drawable.image_loading); + int dpi = activity.getResources().getDisplayMetrics().densityDpi; + int dp; + + if (small) { + dp = SMALL_WIDTH_DP; + } + else { + dp = LARGE_WIDTH_DP; + } + + double scalingDivisor = ART_WIDTH_PX / (dp * (dpi / 160)); + if (scalingDivisor < 1.0) { + // We don't want to make them bigger before draw-time + scalingDivisor = 1.0; + } + LimeLog.info("Art scaling divisor: " + scalingDivisor); + this.activity = activity; - this.loader = new CachedAppAssetLoader(computer, uniqueId, new NetworkAssetLoader(context), + this.loader = new CachedAppAssetLoader(computer, uniqueId, scalingDivisor, + new NetworkAssetLoader(context, uniqueId), new MemoryAssetLoader(), new DiskAssetLoader(context.getCacheDir())); } @@ -102,7 +126,7 @@ public class AppGridAdapter extends GenericGridAdapter { } @Override - public void notifyLoadComplete(Object object, final Bitmap bitmap) { + public void notifyLoadComplete(Object object, Bitmap bitmap) { final WeakReference viewRef = (WeakReference) object; loadingTuples.remove(viewRef); @@ -117,12 +141,13 @@ public class AppGridAdapter extends GenericGridAdapter { return; } + final Bitmap viewBmp = bitmap; activity.runOnUiThread(new Runnable() { @Override public void run() { ImageView view = viewRef.get(); if (view != null) { - view.setImageBitmap(bitmap); + view.setImageBitmap(viewBmp); fadeInImage(view); } } diff --git a/app/src/main/java/com/limelight/grid/assets/CachedAppAssetLoader.java b/app/src/main/java/com/limelight/grid/assets/CachedAppAssetLoader.java index 172b05c2..3635040c 100644 --- a/app/src/main/java/com/limelight/grid/assets/CachedAppAssetLoader.java +++ b/app/src/main/java/com/limelight/grid/assets/CachedAppAssetLoader.java @@ -1,10 +1,12 @@ package com.limelight.grid.assets; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import com.limelight.nvstream.http.ComputerDetails; import com.limelight.nvstream.http.NvApp; +import java.io.InputStream; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -12,21 +14,34 @@ import java.util.concurrent.TimeUnit; public class CachedAppAssetLoader { private final ComputerDetails computer; private final String uniqueId; + private final double scalingDivider; private final ThreadPoolExecutor foregroundExecutor = new ThreadPoolExecutor(8, 8, Long.MAX_VALUE, TimeUnit.DAYS, new LinkedBlockingQueue()); private final ThreadPoolExecutor backgroundExecutor = new ThreadPoolExecutor(2, 2, Long.MAX_VALUE, TimeUnit.DAYS, new LinkedBlockingQueue()); - private final NetworkLoader networkLoader; - private final CachedLoader memoryLoader; - private final CachedLoader diskLoader; + private final NetworkAssetLoader networkLoader; + private final MemoryAssetLoader memoryLoader; + private final DiskAssetLoader diskLoader; - public CachedAppAssetLoader(ComputerDetails computer, String uniqueId, NetworkLoader networkLoader, CachedLoader memoryLoader, CachedLoader diskLoader) { + public CachedAppAssetLoader(ComputerDetails computer, String uniqueId, double scalingDivider, + NetworkAssetLoader networkLoader, MemoryAssetLoader memoryLoader, + DiskAssetLoader diskLoader) { this.computer = computer; this.uniqueId = uniqueId; + this.scalingDivider = scalingDivider; this.networkLoader = networkLoader; this.memoryLoader = memoryLoader; this.diskLoader = diskLoader; } + private static Bitmap scaleBitmapAndRecyle(Bitmap bmp, double scalingDivider) { + Bitmap newBmp = Bitmap.createScaledBitmap(bmp, (int)(bmp.getWidth() / scalingDivider), + (int)(bmp.getHeight() / scalingDivider), true); + if (newBmp != bmp) { + bmp.recycle(); + } + return newBmp; + } + private Runnable createLoaderRunnable(final LoaderTuple tuple, final Object context, final LoadListener listener) { return new Runnable() { @Override @@ -36,7 +51,7 @@ public class CachedAppAssetLoader { return; } - Bitmap bmp = diskLoader.loadBitmapFromCache(tuple); + Bitmap bmp = diskLoader.loadBitmapFromCache(tuple, (int) scalingDivider); if (bmp == null) { // Notify the listener that this may take a while listener.notifyLongLoad(context); @@ -48,20 +63,24 @@ public class CachedAppAssetLoader { return; } - bmp = networkLoader.loadBitmap(tuple); - if (bmp != null) { - break; + InputStream in = networkLoader.getBitmapStream(tuple); + if (in != null) { + // Write the stream straight to disk + diskLoader.populateCacheWithStream(tuple, in); + + // Read it back scaled + bmp = diskLoader.loadBitmapFromCache(tuple, (int) scalingDivider); + if (bmp != null) { + break; + } } // Wait 1 second with a bit of fuzz try { - Thread.sleep((int) (1000 + (Math.random()*500))); - } catch (InterruptedException e) {} - } - - if (bmp != null) { - // Populate the disk cache - diskLoader.populateCache(tuple, bmp); + Thread.sleep((int) (1000 + (Math.random() * 500))); + } catch (InterruptedException e) { + break; + } } } @@ -95,7 +114,7 @@ public class CachedAppAssetLoader { } private LoaderTuple loadBitmapWithContext(NvApp app, Object context, LoadListener listener, boolean background) { - LoaderTuple tuple = new LoaderTuple(computer, uniqueId, app); + LoaderTuple tuple = new LoaderTuple(computer, app); // First, try the memory cache in the current context Bitmap bmp = memoryLoader.loadBitmapFromCache(tuple); @@ -125,15 +144,13 @@ public class CachedAppAssetLoader { public class LoaderTuple { public final ComputerDetails computer; - public final String uniqueId; public final NvApp app; public boolean notified; public boolean cancelled; - public LoaderTuple(ComputerDetails computer, String uniqueId, NvApp app) { + public LoaderTuple(ComputerDetails computer, NvApp app) { this.computer = computer; - this.uniqueId = uniqueId; this.app = app; } @@ -150,15 +167,6 @@ public class CachedAppAssetLoader { } } - public interface NetworkLoader { - public Bitmap loadBitmap(LoaderTuple tuple); - } - - public interface CachedLoader { - public Bitmap loadBitmapFromCache(LoaderTuple tuple); - public void populateCache(LoaderTuple tuple, Bitmap bitmap); - } - public interface LoadListener { // Notifies that the load didn't hit any cache and is about to be dispatched // over the network diff --git a/app/src/main/java/com/limelight/grid/assets/DiskAssetLoader.java b/app/src/main/java/com/limelight/grid/assets/DiskAssetLoader.java index 219ca8a7..2da573de 100644 --- a/app/src/main/java/com/limelight/grid/assets/DiskAssetLoader.java +++ b/app/src/main/java/com/limelight/grid/assets/DiskAssetLoader.java @@ -11,20 +11,21 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -public class DiskAssetLoader implements CachedAppAssetLoader.CachedLoader { +public class DiskAssetLoader { private final File cacheDir; public DiskAssetLoader(File cacheDir) { this.cacheDir = cacheDir; } - @Override - public Bitmap loadBitmapFromCache(CachedAppAssetLoader.LoaderTuple tuple) { + public Bitmap loadBitmapFromCache(CachedAppAssetLoader.LoaderTuple tuple, int sampleSize) { InputStream in = null; Bitmap bmp = null; try { in = CacheHelper.openCacheFileForInput(cacheDir, "boxart", tuple.computer.uuid.toString(), tuple.app.getAppId() + ".png"); - bmp = BitmapFactory.decodeStream(in); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = sampleSize; + bmp = BitmapFactory.decodeStream(in, null, options); } catch (IOException e) { e.printStackTrace(); } finally { @@ -42,13 +43,11 @@ public class DiskAssetLoader implements CachedAppAssetLoader.CachedLoader { return bmp; } - @Override - public void populateCache(CachedAppAssetLoader.LoaderTuple tuple, Bitmap bitmap) { + public void populateCacheWithStream(CachedAppAssetLoader.LoaderTuple tuple, InputStream input) { OutputStream out = null; try { - // PNG ignores quality setting out = CacheHelper.openCacheFileForOutput(cacheDir, "boxart", tuple.computer.uuid.toString(), tuple.app.getAppId() + ".png"); - bitmap.compress(Bitmap.CompressFormat.PNG, 0, out); + CacheHelper.writeInputStreamToOutputStream(input, out); } catch (IOException e) { e.printStackTrace(); } finally { diff --git a/app/src/main/java/com/limelight/grid/assets/MemoryAssetLoader.java b/app/src/main/java/com/limelight/grid/assets/MemoryAssetLoader.java index 4fa26fca..995a4f36 100644 --- a/app/src/main/java/com/limelight/grid/assets/MemoryAssetLoader.java +++ b/app/src/main/java/com/limelight/grid/assets/MemoryAssetLoader.java @@ -5,9 +5,9 @@ import android.util.LruCache; import com.limelight.LimeLog; -public class MemoryAssetLoader implements CachedAppAssetLoader.CachedLoader { +public class MemoryAssetLoader { private static final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); - private static final LruCache memoryCache = new LruCache(maxMemory / 8) { + private static final LruCache memoryCache = new LruCache(maxMemory / 12) { @Override protected int sizeOf(String key, Bitmap bitmap) { // Sizeof returns kilobytes @@ -19,7 +19,6 @@ public class MemoryAssetLoader implements CachedAppAssetLoader.CachedLoader { return tuple.computer.uuid.toString()+"-"+tuple.app.getAppId(); } - @Override public Bitmap loadBitmapFromCache(CachedAppAssetLoader.LoaderTuple tuple) { Bitmap bmp = memoryCache.get(constructKey(tuple)); if (bmp != null) { @@ -28,7 +27,6 @@ public class MemoryAssetLoader implements CachedAppAssetLoader.CachedLoader { return bmp; } - @Override public void populateCache(CachedAppAssetLoader.LoaderTuple tuple, Bitmap bitmap) { memoryCache.put(constructKey(tuple), bitmap); } diff --git a/app/src/main/java/com/limelight/grid/assets/NetworkAssetLoader.java b/app/src/main/java/com/limelight/grid/assets/NetworkAssetLoader.java index 0150b230..b80f09ee 100644 --- a/app/src/main/java/com/limelight/grid/assets/NetworkAssetLoader.java +++ b/app/src/main/java/com/limelight/grid/assets/NetworkAssetLoader.java @@ -2,109 +2,44 @@ package com.limelight.grid.assets; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; -import com.koushikdutta.ion.Ion; import com.limelight.LimeLog; import com.limelight.binding.PlatformBinding; import com.limelight.nvstream.http.ComputerDetails; -import com.limelight.nvstream.http.LimelightCryptoProvider; +import com.limelight.nvstream.http.NvHTTP; +import java.io.IOException; +import java.io.InputStream; import java.net.InetAddress; -import java.net.Socket; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509KeyManager; -import javax.net.ssl.X509TrustManager; - -public class NetworkAssetLoader implements CachedAppAssetLoader.NetworkLoader { +public class NetworkAssetLoader { private final Context context; - private final LimelightCryptoProvider cryptoProvider; - private final SSLContext sslContext; + private final String uniqueId; - public NetworkAssetLoader(Context context) throws NoSuchAlgorithmException, KeyManagementException { + public NetworkAssetLoader(Context context, String uniqueId) throws NoSuchAlgorithmException, KeyManagementException { this.context = context; - - cryptoProvider = PlatformBinding.getCryptoProvider(context); - - sslContext = SSLContext.getInstance("SSL"); - sslContext.init(ourKeyman, trustAllCerts, new SecureRandom()); + this.uniqueId = uniqueId; } - private final TrustManager[] trustAllCerts = new TrustManager[] { - new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - public void checkClientTrusted(X509Certificate[] certs, String authType) {} - public void checkServerTrusted(X509Certificate[] certs, String authType) {} - }}; + public InputStream getBitmapStream(CachedAppAssetLoader.LoaderTuple tuple) { + NvHTTP http = new NvHTTP(getCurrentAddress(tuple.computer), uniqueId, null, PlatformBinding.getCryptoProvider(context)); - private final KeyManager[] ourKeyman = new KeyManager[] { - new X509KeyManager() { - public String chooseClientAlias(String[] keyTypes, - Principal[] issuers, Socket socket) { - return "Limelight-RSA"; - } + InputStream in = null; + try { + in = http.getBoxArt(tuple.app); + } catch (IOException e) {} - public String chooseServerAlias(String keyType, Principal[] issuers, - Socket socket) { - return null; - } - - public X509Certificate[] getCertificateChain(String alias) { - return new X509Certificate[] {cryptoProvider.getClientCertificate()}; - } - - public String[] getClientAliases(String keyType, Principal[] issuers) { - return null; - } - - public PrivateKey getPrivateKey(String alias) { - return cryptoProvider.getClientPrivateKey(); - } - - public String[] getServerAliases(String keyType, Principal[] issuers) { - return null; - } - } - }; - - // Ignore differences between given hostname and certificate hostname - private final HostnameVerifier hv = new HostnameVerifier() { - public boolean verify(String hostname, SSLSession session) { return true; } - }; - - @Override - public Bitmap loadBitmap(CachedAppAssetLoader.LoaderTuple tuple) { - // Set SSL contexts correctly to allow us to authenticate - Ion.getDefault(context).getHttpClient().getSSLSocketMiddleware().setTrustManagers(trustAllCerts); - Ion.getDefault(context).getHttpClient().getSSLSocketMiddleware().setSSLContext(sslContext); - Ion.getDefault(context).getHttpClient().getSSLSocketMiddleware().setHostnameVerifier(hv); - Ion.getDefault(context).getBitmapCache().clear(); - - Bitmap bmp = Ion.with(context) - .load("https://" + getCurrentAddress(tuple.computer).getHostAddress() + ":47984/appasset?uniqueid=" + - tuple.uniqueId + "&appid=" + tuple.app.getAppId() + "&AssetType=2&AssetIdx=0") - .asBitmap() - .tryGet(); - if (bmp != null) { + if (in != null) { LimeLog.info("Network asset load complete: " + tuple); } else { LimeLog.info("Network asset load failed: " + tuple); } - return bmp; + return in; } private static InetAddress getCurrentAddress(ComputerDetails computer) { diff --git a/app/src/main/java/com/limelight/utils/CacheHelper.java b/app/src/main/java/com/limelight/utils/CacheHelper.java index 4bbebd46..581c26fa 100644 --- a/app/src/main/java/com/limelight/utils/CacheHelper.java +++ b/app/src/main/java/com/limelight/utils/CacheHelper.java @@ -38,6 +38,15 @@ public class CacheHelper { return new BufferedOutputStream(new FileOutputStream(openPath(true, root, path))); } + public static void writeInputStreamToOutputStream(InputStream in, OutputStream out) throws IOException { + byte[] buf = new byte[4096]; + int bytesRead; + + while ((bytesRead = in.read(buf)) != -1) { + out.write(buf, 0, bytesRead); + } + } + public static String readInputStreamToString(InputStream in) throws IOException { Reader r = new InputStreamReader(in);