likes
comments
collection
share

Android 小部件(Widget)-系统重启后恢复流程

作者站长头像
站长
· 阅读数 23

本文是 Android Widget(小部件) 系列的第十篇,主要从源码角度是梳理 widget 升级时,系统是如何感知,以及视图是如何更新的。

本系列的目的是通过对 Android 小部件的梳理,了解小部件刷新流程、添加、删除、恢复流程、以及系统发生变化时,小部件是如何适配的,解决在开发小部件过程中遇到的问题。系列文章大部份来自源码的解读,内容非常多,也非常容易遗忘,因此记录分享。

系列文章

一、描述

在手机关机重启后,系统会根据存储小部件信息进行恢复,了解恢复流程有助于解手机重启后,各种奇奇怪怪的问题,同时更加熟悉小部件的运行机制。

二、系统重启后恢复流程


1、初始化AppWidgetService
2、系统解锁后恢复widget

1、初始化AppWidgetService

1.1、启动服务

  • 描述:在SystemServer启动后,在startOtherServices() 调用启动SystemServiceManager 启动AppWidgetService服务。
  • 详细代码
classs  SystemServer {
    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...
        if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)
                || context.getResources().getBoolean(R.bool.config_enableAppWidgetService)) {
            // 启动服务,详看 2
           mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
        }
    ...
    }
}

1.2、SystemServiceManager启动AppWidgetService服务

  • 描述:SystemServiceManager通过反射创建 AppWidgetService 对象并调用起onStart()方法
  • 详细代码:
class SystemServiceManager {

    public SystemService startService(String className) {
        // 根据类名获取class
        final Class<SystemService> serviceClass = loadClassFromLoader(className,
                this.getClass().getClassLoader());
        // 后文有详细代码
        return startService(serviceClass);
    }
    
    public <T extends SystemService> T startService(Class<T> serviceClass) {
            ...
            final T service;
            
            // 获取构造函数,创建对象。
            Constructor<T> constructor = serviceClass.getConstructor(Context.class);
            service = constructor.newInstance(mContext);
             ...
            // 注册服务,调用start,后文有详细代码
            startService(service);
            return service;
      
     }  
        
     public void startService(@NonNull final SystemService service) {
            ...
             // 启动服务 详看 3
            service.onStart();
           ...
        }         
}

class AppWidgetService extends SystemService{

@Override

public void onStart() {

// mImpl为 AppWidgetServiceImpl 详看4

mImpl.onStart();

// 发布服务

publishBinderService(Context.*APPWIDGET_SERVICE*, mImpl);

// 静态对象持有AppWidgetServiceImpl,用于获取widget 的状态,以及恢复

AppWidgetBackupBridge.register(mImpl);

}

}

1.3、AppWidgetServiceImpl onStart 逻辑

  • 描述:AppWidgetServiceImpl onStart 时会获取包管理、闹钟管理、用户管理等一系列管理,计算限制 bitmap 大小限制,注册包改变监听等。
  • 详细代码:
class AppWidgetServiceImpl {
    public void onStart() {
         
        mPackageManager = AppGlobals.getPackageManager();
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
        mKeyguardManager = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
        mDevicePolicyManagerInternal = LocalServices.getService(DevicePolicyManagerInternal.class);
        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
        mSaveStateHandler = BackgroundThread.getHandler();
        mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
        mBackupRestoreController = new BackupRestoreController();
        mSecurityPolicy = new SecurityPolicy();
        // 计算 widget bitmap 可占用内存
        computeMaximumWidgetBitmapMemory();
        // 注册包改变的广播
        registerBroadcastReceiver();
        // 注册设备策略改变的监听
        registerOnCrossProfileProvidersChangedListener();
        // 放入公开的服务池,供各个进程使用
        LocalServices.addService(AppWidgetManagerInternal.class, new AppWidgetManagerLocal());
    }
}

2、系统恢复

2.1、解锁后恢复

  • 描述:解锁系统解锁后通过LocalServices获取小部件服务,调用unlockUser开始恢复小部件。
  • 详细代码
void finishUserUnlockedCompleted(final UserState uss) {
   ...
   //获取小部件服务,开始恢复小部件 详看2
   mInjector.startUserWidgets(userId);
   ... 

}

static class Injector {

    void startUserWidgets(@UserIdInt int userId) {
        AppWidgetManagerInternal awm = LocalServices.getService(AppWidgetManagerInternal.class);
        if (awm != null) {
            // Out of band, because this is called during a sequence with
            // sensitive cross-service lock management
            FgThread.getHandler().post(() -> {
                // 处理用户解锁后的处理
                awm.unlockUser(userId);
            });
        }
    }
}

2.2、恢复小部件

描述:确定小部件加载状态、发送enable、update 广播,并注册定数刷新 详细代码

void handleUserUnlocked(int userId) {
     // 检查uid 是否在使用中
    if (isProfileWithLockedParent(userId)) {
        return;
    }
    // 检查是否解锁
    if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
        Slog.w(TAG, "User " + userId + " is no longer unlocked - exiting");
        return;
    }
    long time = SystemClock.elapsedRealtime();
    synchronized (mLock) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "appwidget ensure");
        //确定小部件的加载状态,详看2.3.1
        ensureGroupStateLoadedLocked(userId);
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "appwidget reload");
        // 加载小部件的遮挡状态,可能和应用的可用时间有关
        reloadWidgetsMaskedStateForGroup(mSecurityPolicy.getGroupParent(userId));
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        final int N = mProviders.size();
        for (int i = 0; i < N; i++) {
            Provider provider = mProviders.get(i);

            // Send broadcast only to the providers of the user.
            if (provider.getUserId() != userId) {
                continue;
            }

            if (provider.widgets.size() > 0) {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        "appwidget init " + provider.id.componentName.getPackageName());
                //发送enable 广播,详看2.3.2
                sendEnableIntentLocked(provider);
                int[] appWidgetIds = getWidgetIds(provider.widgets);
                // 发送更新广播,详看2.3.3
                sendUpdateIntentLocked(provider, appWidgetIds);
                // 注册定时刷新广播
                registerForBroadcastsLocked(provider, appWidgetIds);
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }
    }
    Slog.i(TAG, "Processing of handleUserUnlocked u" + userId + " took "
            + (SystemClock.elapsedRealtime() - time) + " ms");
}

2.3.1、ensureGroupStateLoadedLocked

描述:若已经加载过了则return,若没有加载过则根据uid 获取widgetProvider(过滤带刷新action 的广播),根据uid 获取相应的配置文件,根据配置文件设置widget,并绑定相应的host。放入mWidgets中。

class AppWidgetServiceImpl {
    private void ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked) { 
        // 判断该应用是否处在解锁状态,设备锁 
        if (enforceUserUnlockingOrUnlocked && !isUserRunningAndUnlocked(userId)) { 
            throw new IllegalStateException( 
                    "User " + userId + " must be unlocked for widgets to be available"); 
        } 
        // 判断该应用文件配置是否处在解锁状态 
        if (enforceUserUnlockingOrUnlocked && isProfileWithLockedParent(userId)) { 
            throw new IllegalStateException( 
                    "Profile " + userId + " must have unlocked parent"); 
        } 
        // 获取能用的配置配置id 
        final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId); 
    
    
        // 查看是否有未加载的user 
        // Careful lad, we may have already loaded the state for some 
        // group members, so check before loading and read only the 
        // state for the new member(s). 
        int newMemberCount = 0; 
        final int profileIdCount = profileIds.length; 
        for (int i = 0; i < profileIdCount; i++) { 
            final int profileId = profileIds[i]; 
            // >=0代表已经加载过,标记数组 
            if (mLoadedUserIds.indexOfKey(profileId) >= 0) { 
                profileIds[i] = LOADED_PROFILE_ID; 
            } else { 
                newMemberCount++; 
            } 
        } 
        // 没有新加的 便会return 
        if (newMemberCount <= 0) { 
            return; 
        } 
         // 构建新增加的ProfileId 数组,后续通常在第一次加载的时候执行 
        int newMemberIndex = 0; 
        final int[] newProfileIds = new int[newMemberCount]; 
        for (int i = 0; i < profileIdCount; i++) { 
            final int profileId = profileIds[i]; 
            if (profileId != LOADED_PROFILE_ID) { 
                mLoadedUserIds.put(profileId, profileId); 
                newProfileIds[newMemberIndex] = profileId; 
                newMemberIndex++; 
            } 
        } 
        // 清除provider 和 host 的tag 设置为 TAG_UNDEFINED 
        clearProvidersAndHostsTagsLocked(); 
         // 根据加载ProfileId 获取系统 ResolveInfo 列表, 根据ResolveInfo 构建 ,
         //详看 2.3.1.1      
        loadGroupWidgetProvidersLocked(newProfileIds); 
        // 从系统配置文件/data/system/users/0/appwidgets.xml 加载状态、 
        loadGroupStateLocked(newProfileIds); 
    } 
2.3.1.1 AppWidgetServiceImpl.loadGroupWidgetProvidersLocked

根据刷新的action 在packageManager中查询想要的receiver,根据receiver创建provider。provider 包含关联的widgets、定时广播、AppWidgetProviderInfo

private void loadGroupWidgetProvidersLocked(int[] profileIds) {
    List<ResolveInfo> allReceivers = null;
    Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);

    final int profileCount = profileIds.length;
    for (int i = 0; i < profileCount; i++) {
        final int profileId = profileIds[i];

        List<ResolveInfo> receivers = queryIntentReceivers(intent, profileId);
        if (receivers != null && !receivers.isEmpty()) {
            if (allReceivers == null) {
                allReceivers = new ArrayList<>();
            }
            allReceivers.addAll(receivers);
        }
    }

    final int N = (allReceivers == null) ? 0 : allReceivers.size();
    for (int i = 0; i < N; i++) {
        ResolveInfo receiver = allReceivers.get(i);
        addProviderLocked(receiver);
    }
}

3、相应广播

描述:enable广播和update广播 详细代码:

class AppWidgetServiceImpl {
    private void sendEnableIntentLocked(Provider p) {
        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
        intent.setComponent(p.id.componentName);
        sendBroadcastAsUser(intent, p.id.getProfile());
    }
    
     private void sendUpdateIntentLocked(Provider provider, int[] appWidgetIds) {
        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
        intent.setComponent(provider.id.componentName);
        sendBroadcastAsUser(intent, provider.id.getProfile());
    }
}

到这里,小部件系列所有的文章都已经更新完了,从刷新流程、添加、删除、到恢复流程、以及系统发生变化时视图变化都有介绍,篇幅虽然长但其实里面有很多逻辑都是一样的,当理解完一篇再理解其他就不会那么难,最后希望他可以帮助到很多人解决问题,体现他的价值。