性能优化

Android 性能优化 (一)APK高效瘦身


http://blog.csdn.net/whb20081815/article/details/70140063

Android 性能优化 (二)数据库优化 秒变大神
http://blog.csdn.net/whb20081815/article/details/70142033  

Android 性能优化(三)布局优化 秒变大神


http://blog.csdn.net/whb20081815/article/details/70147958

  Android 性能优化(四)内存优化OOM 秒变大神   http://blog.csdn.net/whb20081815/article/details/70243105 Android 性能优化(五)ANR 秒变大神
http://blog.csdn.net/whb20081815/article/details/70245594 Android 性能优化(六) RelativeLayout和LinearLayout性能比较
http://blog.csdn.net/whb20081815/article/details/74465870
 

Android 性能优化<七>自定义view绘制优化


http://blog.csdn.net/whb20081815/article/details/74474736

原理和源码分析 1.Android Binder 作为 IPC 机制原理和面试回答    http://blog.csdn.net/whb20081815/article/details/74436204 2.  

Android AIDL进程IPC通信 一次就好

http://blog.csdn.net/whb20081815/article/details/70766913

3.

Android AIDL进程IPC通信 一次就好 http://blog.csdn.net/whb20081815/article/details/70766913

4.

 

Android反射(Reflect)完全解析--强势来袭


http://blog.csdn.net/whb20081815/article/details/61198050

5.

 

Android 2分钟学会xUtils 注解 Annotation(实例+原理)

http://blog.csdn.net/whb20081815/article/details/62423840 6.  Android 上下文Context(最权威的官方教程)
http://blog.csdn.net/whb20081815/article/details/70258715 7. Android Activty的加载过程 启动流程 源码分析
http://blog.csdn.net/whb20081815/article/details/76596473


线程: 1). Android 价值千万   java线程专题:Wait¬ify&join&Yield
http://blog.csdn.net/whb20081815/article/details/65627387 2). Android 价值千万    java多线程同步 <二>Callable和Future&FutureTask
http://blog.csdn.net/whb20081815/article/details/65630694 3). Android 价值千万    java多线程<三>生产者消费者模型四种实现方法
http://blog.csdn.net/whb20081815/article/details/65635647  4).

Android 价值千万    java多线程同步 <四> synchronized&Lock&Atomic6种方式


http://blog.csdn.net/whb20081815/article/details/66971983

5).Android 价值千万java多线程同步 <五>CountDownLatch(计数器)和Semaphore(信号量)

http://blog.csdn.net/whb20081815/article/details/68498371

UI,view和动画框架
1). Android 深入理解 View 的绘制流程和机制
http://blog.csdn.net/whb20081815/article/details/62236641 2). 

Android快速理解Activity、View及Window&WindowManager之间关系


http://blog.csdn.net/whb20081815/article/details/62419059
3). Android 动画用法+原理(Property Animation) 酷炫 UI动画
http://blog.csdn.net/whb20081815/article/details/64501074

4).Android 性能优化<七>自定义view绘制优化

 
http://blog.csdn.net/whb20081815/article/details/74474736

wapper :包装
  分类 1.性能优化 2.原理和源码分析------插件化框架的一部分 3.线程模型分析 4.UI,view和动画框架 5.JAVA 面向对象进阶


问题一 1.context启动Activity=======搞定! 2.一个程序里面的每一个模块都可以运行起来。





 

组件化开发就是将一个app分成多个模块,每个模块都是一个组件(Module),开发的过程中我们可以让这些组件相互依赖或者单独调试部分组件等,但是最终发布的时候是将这些组件合并统一成一个apk,这就是组件化开发。
插件化开发和组件化开发略有不用,插件化开发时将整个app拆分成很多模块,这些模块包括一个宿主和多个插件,每个模块都是一个apk(组件化的每个模块是个lib),最终打包的时候将宿主apk和插件apk分开或者联合打包

做插件化真正的目的:是为了去适应并行开发,是为了解耦各个模块,是为了免模块之间的交叉依赖,是为了加快编译速度,从而提高并行开发效率。



  A OP为Aspect Oriented Programming的 缩写,意为:面向切面编程,通过预编译方式和运行期 动态代理 实现程序功能的统一维护的一种技术。

 加入一个app工程只有一个组件,随着app业务的壮大模块越来越多,代码量超10万是很正常的,这个时候我们会遇到以下问题

  • 稍微改动一个模块的一点代码都要编译整个工程,耗时耗力
  • 公共资源、业务、模块混在一起耦合度太高
  • 不方便测试
  • 项目新功能的添加,无法确定与用户匹配性,发生严重异常往往牵一发而动全身,只能紧急发布补丁版本,强制用户进行更新.结果频繁的更新



可以干什么:

  • 热修复,热修复其实也是动态加载原理

  • 换肤,使用动态的资源加载可以实现换肤功能

    实现免安装的功能

  • 还可以通过hook系统的一些类做一些你想做的坏事。

    • 插件化最早出现是因为65535问题出现的,用于查分多个dex并动态加载dex来防止65535问题

    • 现在很多公司用插件化来做模块的动态加载,这样既能实现web端一样的随时更新,还能减少apk包的体积,其实就是加载一个未安装的apk。




Android插件化开发框架

1. 360插件化框架======= RePlugin有什么用  RePlugin解决的是各个功能模块能独立升级,又能需要和宿主、插件之间有一定交互和耦合
在阅读他们开源的东西的时候,确实是我读过开源项目里面算是友好的, 至少注释是这样子的. 尤其是有阿里atlas 这种反面例子做对比
强大的介绍
http://news.163.com/17/0701/21/CO9PEL3400014AEE.html 官方下载地址: https://github.com/Qihoo360/RePlugin/wiki 2.滴滴出行插件化框架
3. 携程插件化框架---- DynamicAPK       之后曾和玉刚聊天,他十分感慨当年如何举步维艰地开发这个框架。我当时在途牛工作,使用了这个Android插件化框架。 任玉刚的:dynamic-load-apk,这个项目使用的是 一种代理的方式去实现   4.Atlas  阿里的
5. ACDD插件化框架 6.DroidPlugin360的老式方案----------------- DroidPlugin,这个项目是通过hook系统类来实现   7. Android-Plugin-Framework
8. DL APK动态加载框架



(女娲)







四个月前(2015年8月初) , BunnyBlue开源了一个名为OpenAtlas的插件化框架, 这个插件化的来源可能并非所有人知晓, 我在这里概括一下:

2013年, 朱碧军同学在阿里的一次技术沙龙中分享了一个插件化框架: Atlas ,这个框架用在淘宝的Android客户端,没有开源,沙龙中也没有对该插件化的具体实现做讲解.(阿里技术沙龙)

15年, BunnyBlue同学在研究淘宝客户端时发现,Atlas框架没有混淆的十分彻底(在com.android.atlas下),于是花了一些时间对其中代码的实现进行了逆向,并在8月初开源了这一成果,并取名为OpenAtlas.

后来,由于涉及到一些代码来源方面的问题, OpenAtlas项目关闭,后改名为:ACCD(bunnyblue/ACDD · GitHub).



需要解决的问题:(代码加载和资源加载)
  • 编译期:资源和代码的编译
  • 运行时:资源和代码的加载
  •    还有一个问题就是对四大组件的生命周期管理
Android的资源编译依赖一个强大的命令行工具:aapt,它位于 /build-tools//aapt

插件化原理解读:
类的加载可以使用Java的 ClassLoader 机制,但是对于Android来说,并不是说类加载进来就可以用了,很多组件都是有“生命”的 ;因此对于这些有血有肉的类,必须给它们注入活力,也就是所谓的 组件生命周期管理

另外,如何管理加载进来的类也是一个问题。假设多个插件依赖了相同的类,是抽取公共依赖进行管理还是插件单独依赖?这就是 ClassLoader的管理问题


资源加载

资源加载方案大家使用的原理都差不多,都是用AssetManager的隐藏方法addAssetPath;但是,不同插件的资源如何管理?是公用一套资源还是插件独立资源?共用资源如何避免资源冲突?对于资源加载,有的方案共用一套资源并采用资源分段机制解决冲突(要么修改aapt要么添加编译插件);有的方案选择独立资源,不同插件管理自己的资源。

目前国内开源的较成熟的插件方案有DL和DroidPlugin;但是DL方案仅仅对Frameworl的表层做了处理,严重依赖that语法,编写插件代码和主程序代码需单独区分;而DroidPlugin通过Hook增强了Framework层的很多系统服务,开发插件就跟开发独立app差不多;就拿Activity生命周期的管理来说,DL的代理方式就像是牵线木偶,插件只不过是操纵傀儡而已;而DroidPlugin则是借尸还魂,插件是有血有肉的系统管理的真正组件;DroidPlugin Hook了系统几乎所有的Sevice,欺骗了大部分的系统API;掌握这个Hook过程需要掌握很多系统原理,因此学习DroidPlugin对于整个Android FrameWork层大有裨益。

接下来的一系列文章将以DroidPlugin为例讲解插件框架的原理,揭开插件化的神秘面纱;同时还能帮助深入理解Android Framewrok;主要内容如下:


需要学习的一些类:

1.ActivityThread

2.Instrumentation

3.ActivityManager

4.ActivityManagerServiche

5.PackageManagerServic

6.ServiceManager

7.ActivityManagerNative

8.ApplicationThread

如果你不清楚ActivityManagerActivityManagerService以及ActivityManagerNative之间的关系;建议先仔细阅读我之前关于Binder的文章 Binder学习指南


流程

1.Activity的启动流程

2.service的启动加载


CLassLoader机制,JAVA虚拟机的原理!



罗迪 http://www.infoq.com/cn/articles/android-plug-ins-from-entry-to-give-up

主要利用 Java ClassLoader 的原理, 对于 Android 来说是 DexClassLoader,如下
无非是代理Activity加动态加载类和用AssetManager加载资源

第五点更重要,做Android插件化需要控制两个地方。首先是插件Dex的加载,如何把插件Dex中的类加载到内存?另外是资源加载的问题。 插件可能是apk也可能是so格式,不管哪一种,都不会生成R.id,从而没办法使用。这个问题有好几种解决方案。 一种是是重写Context的getAsset、getResource之类的方法,偷换概念,让插件读取插件里的资源,但缺点就是宿主和插件的资源id会冲突,需要重写AAPT

来源: http://www.infoq.com/cn/articles/android-plug-ins-from-entry-to-give-up


全部的原理过程:
http://blog.csdn.net/yulong0809/article/details/59113935
http://blog.csdn.net/amurocrash/article/details/46965419



准备知识: 1.APK的安装流程       数组     attach 2.Activity的启动流程


1.binder机制 2.动态代理,AIDL里面用的就是binder机制!


Hook机制之动态代理
public static void attachContext() throws Exception{    // 先获取到当前的ActivityThread对象    Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");    Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");    currentActivityThreadMethod.setAccessible(true);    //currentActivityThread是一个static函数所以可以直接invoke,不需要带实例参数    Object currentActivityThread = currentActivityThreadMethod.invoke(null);    // 拿到原始的 mInstrumentation字段    Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation");    mInstrumentationField.setAccessible(true);    Instrumentation mInstrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread);    // 创建代理对象    Instrumentation evilInstrumentation = new EvilInstrumentation(mInstrumentation);    // 偷梁换柱    mInstrumentationField.set(currentActivityThread, evilInstrumentation);}


我们需要修改它的 mInstrumentation 这个字段为我们的代理对象,我们先实现这个代理对象, 由于JDK动态代理只支持接口,而这个 Instrumentation 是一个类,没办法,我们只有手动写静态代理类,覆盖掉原始的方法即可
Ok,有了代理对象,我们要做的就是偷梁换柱!代码比较简单,采用反射直接修改:


public class EvilInstrumentation extends Instrumentation {    private static final String TAG = "EvilInstrumentation";    // ActivityThread中原始的对象, 保存起来    Instrumentation mBase;    public EvilInstrumentation(Instrumentation base) {        mBase = base;    }    public ActivityResult execStartActivity(            Context who, IBinder contextThread, IBinder token, Activity target,            Intent intent, int requestCode, Bundle options) {        // Hook之前, XXX到此一游!        Log.d(TAG, "\n执行了startActivity, 参数如下: \n" + "who = [" + who + "], " +                "\ncontextThread = [" + contextThread + "], \ntoken = [" + token + "], " +                "\ntarget = [" + target + "], \nintent = [" + intent +                "], \nrequestCode = [" + requestCode + "], \noptions = [" + options + "]");        // 开始调用原始的方法, 调不调用随你,但是不调用的话, 所有的startActivity都失效了.        // 由于这个方法是隐藏的,因此需要使用反射调用;首先找到这个方法        try {            Method execStartActivity = Instrumentation.class.getDeclaredMethod(                    "execStartActivity",                    Context.class, IBinder.class, IBinder.class, Activity.class,                    Intent.class, int.class, Bundle.class);            execStartActivity.setAccessible(true);            return (ActivityResult) execStartActivity.invoke(mBase, who,                    contextThread, token, target, intent, requestCode, options);        } catch (Exception e) {            // 某该死的rom修改了  需要手动适配            throw new RuntimeException("do not support!!! pls adapt it");        }    }

总结:用代理对象替换 原始对象,通过反射的方式得到方法,
(静态代理还是动态代理)替代以前的 Instrumentation对象,在执行方法之前做了一些操作,
动态代理?
// 招代理women = (Shopping) Proxy.newProxyInstance(Shopping.class.getClassLoader(),        women.getClass().getInterfaces(), new ShoppingHandler(women));

执行启动程序的时候先调用了打印(仅仅为了演示),如下

Log.d(TAG, "\n执行了startActivity, 参数如下: \n" + "who = [" + who + "], " +        "\ncontextThread = [" + contextThread + "], \ntoken = [" + token + "], " +        "\ntarget = [" + target + "], \nintent = [" + intent +        "], \nrequestCode = [" + requestCode + "], \noptions = [" + options + "]");

系统服务的获取过程


ActivityManager activityManager=(ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);

@Overridepublic Object getSystemService(String name) {    return SystemServiceRegistry.getSystemService(this, name);}
public static Object getSystemService(ContextImpl ctx, String name) {    ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);    return fetcher != null ? fetcher.getService(ctx) : null;}


tatic {    registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,            new CachedServiceFetcher() {        @Override        public AccessibilityManager createService(ContextImpl ctx) {            return AccessibilityManager.getInstance(ctx);        }});    registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,            new CachedServiceFetcher() {        @Override        public CaptioningManager createService(ContextImpl ctx) {            return new CaptioningManager(ctx);        }});

registerService(Context.POWER_SERVICE, PowerManager.class,        new CachedServiceFetcher() {    @Override    public PowerManager createService(ContextImpl ctx) {        IBinder b = ServiceManager.getService(Context.POWER_SERVICE);        IPowerManager service = IPowerManager.Stub.asInterface(b);        if (service == null) {            Log.wtf(TAG, "Failed to get power manager service.");        }        return new PowerManager(ctx.getOuterContext(),                service, ctx.mMainThread.getHandler());    }});


    因此,通过分析我们得知,系统Service的使用其实就分为两步:
IBinder b = ServiceManager.getService("service_name"); // 获取原始的IBinder对象IXXInterface in = IXXInterface.Stub.asInterface(b); // 转换为Service接口

public class BinderHookHelper {    public static void hookClipboardService() throws Exception {        final String CLIPBOARD_SERVICE = "clipboard";        // 下面这一段的意思实际就是: ServiceManager.getService("clipboard");        // 只不过 ServiceManager这个类是@hide        Class<?> serviceManager = Class.forName("android.os.ServiceManager");        Method getService = serviceManager.getDeclaredMethod("getService", String.class);        // ServiceManager里面管理的原始的Clipboard Binder对象        // 一般来说这是一个Binder代理对象        IBinder rawBinder = (IBinder) getService.invoke(null, CLIPBOARD_SERVICE);        // Hook 掉这个Binder代理对象的 queryLocalInterface 方法        // 然后在 queryLocalInterface 返回一个IInterface对象, hook掉我们感兴趣的方法即可.        IBinder hookedBinder = (IBinder) Proxy.newProxyInstance(serviceManager.getClassLoader(),                new Class<?>[] { IBinder.class },                new BinderProxyHookHandler(rawBinder));        // 把这个hook过的Binder代理对象放进ServiceManagercache里面        // 以后查询的时候 会优先查询缓存里面的Binder, 这样就会使用被我们修改过的Binder        Field cacheField = serviceManager.getDeclaredField("sCache");        cacheField.setAccessible(true);        Map, IBinder> cache = (Map) cacheField.get(null);        cache.put(CLIPBOARD_SERVICE, hookedBinder);    }

public class BinderProxyHookHandler implements InvocationHandler {    private static final String TAG = "BinderProxyHookHandler";    // 绝大部分情况下,这是一个BinderProxy对象    // 只有当Service和我们在同一个进程的时候才是Binder本地对象    // 这个基本不可能    IBinder base;    Class<?> stub;    Class<?> iinterface;    public BinderProxyHookHandler(IBinder base) {        this.base = base;        try {            this.stub = Class.forName("android.content.IClipboard$Stub");            this.iinterface = Class.forName("android.content.IClipboard");        } catch (ClassNotFoundException e) {            e.printStackTrace();        }    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        if ("queryLocalInterface".equals(method.getName())) {            Log.d(TAG, "hook queryLocalInterface");            // 这里直接返回真正被Hook掉的Service接口            // 这里的 queryLocalInterface 就不是原本的意思了            // 我们肯定不会真的返回一个本地接口, 因为我们接管了 asInterface方法的作用            // 因此必须是一个完整的 asInterface 过的 IInterface对象, 既要处理本地对象,也要处理代理对象            // 这只是一个Hook点而已, 它原始的含义已经被我们重定义了; 因为我们会永远确保这个方法不返回null            //  IClipboard.Stub.asInterface 永远走到if语句的else分支里面            return Proxy.newProxyInstance(proxy.getClass().getClassLoader(),

public class BinderHookHandler implements InvocationHandler {    private static final String TAG = "BinderHookHandler";    // 原始的Service对象 (IInterface)    Object base;    public BinderHookHandler(IBinder base, Class<?> stubClass) {        try {            Method asInterfaceMethod = stubClass.getDeclaredMethod("asInterface", IBinder.class);            // IClipboard.Stub.asInterface(base);            this.base = asInterfaceMethod.invoke(null, base);        } catch (Exception e) {            throw new RuntimeException("hooked failed!");        }    }    @TargetApi(Build.VERSION_CODES.HONEYCOMB)    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        // 把剪切版的内容替换为 "you are hooked"        if ("getPrimaryClip".equals(method.getName())) {            Log.d(TAG, "hook getPrimaryClip");            return ClipData.newPlainText(null, "you are hooked");        }        // 欺骗系统,使之认为剪切版上一直有内容        if ("hasPrimaryClip".equals(method.getName())) {            return true;        }        return method.invoke(base, args);

特点:实现了多级代理!

1.要修改粘贴板的方法,需要得到manager对象 manager对象通过 ActivityManager activityManager=(ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE); 得到,manager又是通过ServiceManager来操作的。
目的:把 ServiceManager操作的Manager替换成我们的代理ProxyManager! ProxyManager里面的方法又修改!

生命周期: 为什么需要一直与AMS进行通信?哪些操作是在AMS中进行的?其实 AMS 正如名字所说,管理所有的“活动”,整个系统的Activity堆栈,Activity生命周期回调都是由AMS所在的系统进程system_server帮开发者完成的;Android的Framework层帮忙完成了诸如生命周期管理等





AMSActivityThread之间对于Activity的生命周期的交互,并没有直接使用Activity对象进行交互,而是使用一个token来标识,

这个token是binder对象,因此可以方便地跨进程传递。Activity里面有一个成员变量mToken代表的就是它,token可以唯一地标识一个Activity对象,它在Activity的attach方法里面初始化;

AMS处理Activity的任务栈的时候,使用这个token标记Activity




  • Hook机制之Binder Hook
  • Hook机制之动态代理
  • Hook机制之AMS&PMS
  • Activity生命周期管理
  • 插件加载机制
  • 广播的管理方式
  • Service的插件化
  • ContentProvider的插件化
  • DroidPlugin插件通信机制
  • 插件机制之资源管理
  • 不同插件框架方案对比
  • 插件化的未来

第二阶段



Hook机制

hook,又叫钩子,通常是指对一些方法进行拦截

大致思路:

1.找到需要Hook方法的系统类

2.利用代理模式来代理系统类的运行拦截我们需要拦截的方法

3.使用反射的方法把这个系统类替换成你的代理类




大神推荐:   http://weishu.me/2016/01/28/understand-plugin-framework-overview/



分包原理 http://www.cnblogs.com/chenxibobo/p/6076459.html
http://blog.csdn.net/vurtne_ye/article/details/39666381

http://mp.weixin.qq.com/s?__biz=MzI0MjE3OTYwMg==&mid=2649547588&idx=1&sn=71a5eaf53c601a44ddc582ef3d3de44d&scene=21#wechat_redirect

更多相关文章

  1. LayoutInflater源码分析
  2. Android利用soap WSDL与Webservice通信
  3. Android之AsyncTask源码分析(第五篇:execute方法只能执行一次的原
  4. android加密、签名相关
  5. Android(安卓)Jetpack之Paging初探
  6. android ViewPager,ViewFlipper,ViewFlow实现左右滑动
  7. Android(安卓)Java 获取剪切板的内容,MD5加密。
  8. Android(安卓)Activity的显示过程简述
  9. Android(安卓)自定义Viewpager滑动速度

随机推荐

  1. 发生android.view.ViewRoot$CalledFromWr
  2. Android开源项目集合
  3. android开发每日汇总【2011-11-30】
  4. Android创建ShortCut
  5. 收藏自己喜欢的框架-Android
  6. Android(安卓)Settings 开发(一) -- EditTe
  7. Android睡眠助手 实现情景模式的切换
  8. 项目打包后出现第三方JAR包找不到
  9. oauth 授权显示无权访问页面问题的解决方
  10. Android(安卓)NDK 开发+cygwin 的安装 +e