全新版FRIDA与安卓 应用安全与逆向实战宝典
全新版FRIDA与安卓 应用安全与逆向实战宝典
download:https://www.zxit666.com/6432/
1、CompletableFuture引见
CompletableFuture对象是JDK1.8版本新引入的类,这个类完成了两个接口,一个是Future接口,一个是CompletionStage接口。
CompletionStage接口是JDK1.8版本提供的接口,用于异步执行中的阶段处置,CompletionStage定义了一组接口用于在一个阶段执行完毕之后,要么继续执行下一个阶段,要么对结果停止转换产生新的结果等,普通来说要执行下一个阶段都需求上一个阶段正常完成,这个类也提供了对异常结果的处置接口
2、CompletableFuture的API
2.1 提交任务
在CompletableFuture中提交任务有以下几种方式:
public static CompletableFuture<Void> runAsync(Runnable runnable)public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
这四个办法都是用来提交任务的,不同的是supplyAsync提交的任务有返回值,runAsync提交的任务没有返回值。两个接口都有一个重载的办法,第二个入参为指定的线程池,假如不指定,则默许运用ForkJoinPool.commonPool()线程池。在运用的过程中尽量依据不同的业务来指定不同的线程池,便当对不同线程池停止监控,同时防止业务共用线程池互相影响。
2.2 结果转换
2.2.1 thenApply
public CompletableFuture thenApply(Function<? super T,? extends U> fn)public CompletableFuture thenApplyAsync(Function<? super T,? extends U> fn)public CompletableFuture thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
thenApply这一组函数入参是Function,意义是将上一个CompletableFuture执行结果作为入参,再次停止转换或者计算,重新返回一个新的值。
2.2.2 handle
public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn)public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn)public <U> CompletableFuture<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)
handle这一组函数入参是BiFunction,该函数式接口有两个入参一个返回值,意义是处置上一个CompletableFuture的处置结果,同时假如有异常,需求手动处置异常。
2.2.3 thenRun
public CompletableFuturethenRun(Runnable action)public CompletableFuturethenRunAsync(Runnable action)public CompletableFuturethenRunAsync(Runnable action, Executor executor)
thenRun这一组函数入参是Runnable函数式接口,该接口无需入参和出参,这一组函数是在上一个CompletableFuture任务执行完成后,在执行另外一个接口,不需求上一个任务的结果,也不需求返回值,只需求在上一个任务执行完成后执行即可。
2.2.4 thenAccept
public CompletableFuture<Void> thenAccept(Consumer<? super T> action)public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)
thenAccept这一组函数的入参是Consumer,该函数式接口有一个入参,没有返回值,所以这一组接口的意义是处置上一个CompletableFuture的处置结果,但是不返回结果。
2.2.5 thenAcceptBoth
public CompletableFuturethenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action)public CompletableFuturethenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action)public CompletableFuturethenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action, Executor executor)
thenAcceptBoth这一组函数入参包括CompletionStage以及BiConsumer,CompletionStage是JDK1.8新增的接口,在JDK中只要一个完成类:CompletableFuture,所以第一个入参就是CompletableFuture,这一组函数是用来承受两个CompletableFuture的返回值,并将其组合到一同。BiConsumer这个函数式接口有两个入参,并且没有返回值,BiConsumer的第一个入参就是调用方CompletableFuture的执行结果,第二个入参就是thenAcceptBoth接口入参的CompletableFuture的执行结果。所以这一组函数意义是将两个CompletableFuture执行结果兼并到一同。
2.2.6 thenCombine
public <U,V> CompletableFuturethenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)public <U,V> CompletableFuturethenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)public <U,V> CompletableFuturethenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn, Executor executor)
thenCombine这一组函数和thenAcceptBoth相似,入参都包含一个CompletionStage,也就是CompletableFuture对象,意义也是组合两个CompletableFuture的执行结果,不同的是thenCombine的第二个入参为BiFunction,该函数式接口有两个入参,同时有一个返回值。所以与thenAcceptBoth不同的是,thenCombine将两个任务结果兼并后会返回一个全新的值作为出参。
2.2.7 thenCompose
public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn)public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn, Executor executor)
thenCompose这一组函数意义是将调用方的执行结果作为Function函数的入参,同时返回一个新的CompletableFuture对象。
2.3 回调办法
public CompletableFuturewhenComplete(BiConsumer<? super T, ? super Throwable> action)public CompletableFuturewhenCompleteAsync(BiConsumer<? super T, ? super Throwable> action)public CompletableFuturewhenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)
whenComplete办法意义是当上一个CompletableFuture对象任务执行完成后执行该办法。BiConsumer函数式接口有两个入参没有返回值,这两个入参第一个是CompletableFuture任务的执行结果,第二个是异常信息。表示处置上一个任务的结果,假如有异常,则需求手动处置异常,与handle办法的区别在于,handle办法的BiFunction是有返回值的,而BiConsumer是没有返回值的。
以上办法都有一个带有Async的办法,带有Async的办法表示是异步执行的,会将该任务放到线程池中执行,同时该办法会有一个重载的办法,最后一个参数为Executor,表示异步执行能够指定线程池执行。为了便当停止控制,最好在运用CompletableFuture时手动指定我们的线程池。
2.4 异常处置
public CompletableFutureexceptionally(Function<Throwable, ? extends T> fn)
exceptionally是用来处置异常的,当任务抛出异常后,能够经过exceptionally来停止处置,也能够选择运用handle来停止处置,不过两者有些不同,hand是用来处置上一个任务的结果,假如有异常状况,就处置异常。而exceptionally能够放在CompletableFuture处置的最后,作为兜底逻辑来处置未知异常。
2.5 获取结果
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
allOf是需求入参中一切的CompletableFuture任务执行完成,才会停止下一步;
anyOf是入参中任何一个CompletableFuture任务执行完成都能够执行下一步。
public T get() throws InterruptedException, ExecutionExceptionpublic T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutExceptionpublic T getNow(T valueIfAbsent)public T join()
get办法一个是不带超时时间的,一个是带有超时时间的。
getNow办法则是立刻返回结果,假如还没有结果,则返回默许值,也就是该办法的入参。
join办法是不带超时时间的等候任务完成。
3、CompletableFuture原理
join办法同样表示获取结果,但是join与get办法有什么区别呢。
public T join() { Object r; return reportJoin((r = result) == null ? waitingGet(false) : r); }public T get() throws InterruptedException, ExecutionException { Object r; return reportGet((r = result) == null ? waitingGet(true) : r); }public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { Object r; long nanos = unit.toNanos(timeout); return reportGet((r = result) == null ? timedGet(nanos) : r); }public T getNow(T valueIfAbsent) { Object r; return ((r = result) == null) ? valueIfAbsent : reportJoin(r); }
以上是CompletableFuture类中两个办法的代码,能够看到两个办法简直一样。区别在于reportJoin/reportGet,waitingGet办法是分歧的,只不过参数不一样,我们在看下reportGet与reportJoin办法。
private static T reportGet(Object r) throws InterruptedException, ExecutionException { if (r == null) // by convention below, null means interrupted throw new InterruptedException(); if (r instanceof AltResult) { Throwable x, cause; if ((x = ((AltResult)r).ex) == null) return null; if (x instanceof CancellationException) throw (CancellationException)x; if ((x instanceof CompletionException) && (cause = x.getCause()) != null) x = cause; throw new ExecutionException(x); } T t = (T) r; return t; }private static T reportJoin(Object r) { if (r instanceof AltResult) { Throwable x; if ((x = ((AltResult)r).ex) == null) return null; if (x instanceof CancellationException) throw (CancellationException)x; if (x instanceof CompletionException) throw (CompletionException)x; throw new CompletionException(x); } ("unchecked") T t = (T) r; return t; }
能够看到这两个办法很相近,reportGet办法判别了r对象能否为空,并抛出了中缀异常,而reportJoin办法没有判别,同时reportJoin抛出的都是运转时异常,所以join办法也是无需手动捕获异常的。
我们在看下waitingGet办法
private Object waitingGet(boolean interruptible) { Signaller q = null; boolean queued = false; int spins = -1; Object r; while ((r = result) == null) { if (spins < 0) spins = SPINS; else if (spins > 0) { if (ThreadLocalRandom.nextSecondarySeed() >= 0) --spins; } else if (q == null) q = new Signaller(interruptible, 0L, 0L); else if (!queued) queued = tryPushStack(q); else if (interruptible && q.interruptControl < 0) { q.thread = null; cleanStack(); return null; } else if (q.thread != null && result == null) { try { ForkJoinPool.managedBlock(q); } catch (InterruptedException ie) { q.interruptControl = -1; } } } if (q != null) { q.thread = null; if (q.interruptControl < 0) { if (interruptible) r = null; // report interruption else Thread.currentThread().interrupt(); } } postComplete(); return r; }
该waitingGet办法是经过while的方式循环判别能否任务曾经完成并产生结果,假如结果为空,则会不断在这里循环,这里需求留意的是在这里初始化了一下spins=-1,当第一次进入while循环的时分,spins是-1,这时会将spins赋值为一个常量,该常量为SPINS。
private static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ? 1 << 8 : 0);
这里判别可用CPU数能否大于1,假如大于1,则该常量为 1<< 8,也就是256,否则该常量为0。
第二次进入while循环的时分,spins是256大于0,这里做了减一的操作,下次进入while循环,假如还没有结果,仍然是大于0继续做减一的操作,此处用来做短时间的自旋等候结果,只要当spins等于0,后续会进入正常流程判别。
我们在看下timedGet办法的源码
private Object timedGet(long nanos) throws TimeoutException { if (Thread.interrupted()) return null; if (nanos <= 0L) throw new TimeoutException(); long d = System.nanoTime() + nanos; Signaller q = new Signaller(true, nanos, d == 0L ? 1L : d); // avoid 0 boolean queued = false; Object r; // We intentionally don't spin here (as waitingGet does) because // the call to nanoTime() above acts much like a spin. while ((r = result) == null) { if (!queued) queued = tryPushStack(q); else if (q.interruptControl < 0 || q.nanos <= 0L) { q.thread = null; cleanStack(); if (q.interruptControl < 0) return null; throw new TimeoutException(); } else if (q.thread != null && result == null) { try { ForkJoinPool.managedBlock(q); } catch (InterruptedException ie) { q.interruptControl = -1; } } } if (q.interruptControl < 0) r = null; q.thread = null; postComplete(); return r; }
timedGet办法仍然是经过while循环的方式来判别能否曾经完成,timedGet办法入参为一个纳秒值,并经过该值计算出一个deadline截止时间,当while循环还未获取到任务结果且曾经到达截止时间,则抛出一个TimeoutException异常。
4、CompletableFuture完成多线程任务
这里我们经过CompletableFuture来完成一个多线程处置异步任务的例子。
这里我们创立10个任务提交到我们指定的线程池中执行,并等候这10个任务全部执行终了。
每个任务的执行流程为第一次先执行加法,第二次执行乘法,假如发作异常则返回默许值,当10个任务执行完成后依次打印每个任务的结果。
<button type="button" class="btn btn-dark rounded-0 sflex-center copyCode" data-toggle="tooltip" data-placement="top" data-clipboard-text="public void demo() throws InterruptedException, ExecutionException, TimeoutException { // 1、自定义线程池 ExecutorService executorService = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100)); // 2、汇合保管future对象 List<CompletableFuture> futures = new ArrayList<>(10); for (int i = 0; i < 10; i++) { int finalI = i; CompletableFuture future = CompletableFuture // 提交任务到指定线程池 .supplyAsync(() -> this.addValue(finalI), executorService) // 第一个任务执行结果在此处停止处置 .thenApplyAsync(k -> this.plusValue(finalI, k), executorService) // 任务执行异常时处置异常并返回默许值 .exceptionally(e -> this.defaultValue(finalI, e)); // future对象添加到汇合中 futures.add(future); } // 3、等候一切任务执行完成,此处最好加超时时间 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(5, TimeUnit.MINUTES); for (CompletableFuture future : futures) { Integer num = future.get(); System.out.println("任务执行结果为:" + num); } System.out.println("任务全部执行完成!"); } private Integer addValue(Integer index) { System.out.println("第" + index + "个任务第一次执行"); if (index == 3) { int value = index / 0; } return index + 3; } private Integer plusValue(Integer index, Integer num) { System.out.println("第" + index + "个任务第二次执行,上次执行结果:" + num); return num * 10; } private Integer defaultValue(Integer index, Throwable e) { System.out.println("第" + index + "个任务执行异常!" + e.getMessage()); e.printStackTrace(); return 10; } " aria-label="复制" data-bs-original-title="复制" style="margin: 0px; font-family: var(--bs-btn-font-family);font-size:undefined(--bs-btn-font-size); line-height: var(--bs-btn-line-height); appearance: button; --bs-btn-padding-x:0.75rem; --bs-btn-padding-y:0.375rem; --bs-btn-font-family: ; --bs-btn-font-size:1rem; --bs-btn-font-weight:400; --bs-btn-line-height:1.5; --bs-btn-color:#fff; --bs-btn-bg:#212529; --bs-btn-border-width:1px; --bs-btn-border-color:#212529; --bs-btn-border-radius:0.375rem; --bs-btn-hover-border-color:#373b3e; --bs-btn-box-shadow:inset 0 1px 0 hsla(0,0%,100%,0.15),0 1px 1px rgba(0,0,0,0.075); --bs-btn-disabled-opacity:0.65; --bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb),0.5); display: flex; padding: 0px; font-weight: var(--bs-btn-font-weight); vertical-align: middle; cursor: pointer; user-select: none; border: var(--bs-btn-border-width) solid var(--bs-btn-border-color); transition: color 0.15s ease-in-out 0s, background-color 0.15s ease-in-out 0s, border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s; --bs-btn-hover-color:#fff; --bs-btn-hover-bg:#424649; --bs-btn-focus-shadow-rgb:66,70,73; --bs-btn-active-color:#fff; --bs-btn-active-bg:#4d5154; --bs-btn-active-border-color:#373b3e; --bs-btn-active-shadow:inset 0 3px 5px rgba(0,0,0,0.125); --bs-btn-disabled-color:#fff; --bs-btn-disabled-bg:#212529; --bs-btn-disabled-border-color:#212529; justify-content: center; align-items: center; width: 1.5rem; height: 1.5rem; border-radius: 0px !important;">
public void demo() throws InterruptedException, ExecutionException, TimeoutException { // 1、自定义线程池 ExecutorService executorService = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100)); // 2、汇合保管future对象 List<CompletableFuture<Integer>> futures = new ArrayList<>(10); for (int i = 0; i < 10; i++) { int finalI = i; CompletableFuture<Integer> future = CompletableFuture // 提交任务到指定线程池 .supplyAsync(() -> this.addValue(finalI), executorService) // 第一个任务执行结果在此处停止处置 .thenApplyAsync(k -> this.plusValue(finalI, k), executorService) // 任务执行异常时处置异常并返回默许值 .exceptionally(e -> this.defaultValue(finalI, e)); // future对象添加到汇合中 futures.add(future); } // 3、等候一切任务执行完成,此处最好加超时时间 CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).get(5, TimeUnit.MINUTES); for (CompletableFuture<Integer> future : futures) { Integer num = future.get();