Warning: Can't synchronize with repository "(default)" (No changeset 96d22ec3fa3ef6de3ea8dc0d7d398adc9aa071cf in the repository). Look in the Trac log for more information.

source: fsousaged/src/plugins/controller/plugin.vala @ 2e3ea54

Revision 2e3ea54, 15.1 KB checked in by Michael 'Mickey' Lauer <mickey@…>, 4 years ago (diff)

ousaged: controller: remove debug messages

  • Property mode set to 100644
Line 
1/*
2 * Generic Resource Controller
3 *
4 * Written by Michael 'Mickey' Lauer <mlauer@vanille-media.de>
5 * All Rights Reserved
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 *
21 */
22
23using GLib;
24using Gee;
25
26internal const string DBUS_BUS_NAME = "org.freedesktop.DBus";
27internal const string DBUS_BUS_PATH = "/org/freedesktop/DBus";
28internal const string DBUS_BUS_INTERFACE = "org.freedesktop.DBus";
29
30internal const string RESOURCE_INTERFACE = "org.freesmartphone.Resource";
31
32internal const string CONFIG_SECTION = "fsousage";
33
34namespace Usage
35{
36/**
37 * Enum for resource status
38 **/
39public enum ResourceStatus
40{
41    UNKNOWN,
42    ENABLING,
43    ENABLED,
44    SUSPENDING,
45    SUSPENDED,
46    RESUMING,
47    DISABLING,
48    DISABLED
49}
50
51/**
52 * Helper class encapsulating a registered resource
53 **/
54public class Resource
55{
56    public string name;
57    public DBus.BusName busname;
58    public DBus.ObjectPath objectpath;
59    public ResourceStatus status;
60    public FreeSmartphone.UsageResourcePolicy policy;
61    public ArrayList<string> users;
62
63    private FreeSmartphone.Resource proxy;
64
65    public Resource( string name, DBus.BusName busname, DBus.ObjectPath objectpath )
66    {
67        this.name = name;
68        this.busname = busname;
69        this.objectpath = objectpath;
70        this.status = ResourceStatus.UNKNOWN;
71        this.policy = FreeSmartphone.UsageResourcePolicy.AUTO;
72        this.users = new ArrayList<string>( str_equal );
73
74        proxy = dbusconn.get_object( busname, objectpath, RESOURCE_INTERFACE ) as FreeSmartphone.Resource;
75        // workaround until vala 0.7.4
76        proxy.ref();
77
78        //message( "Resource %s served by %s @ %s created", name, busname, objectpath );
79    }
80
81    ~Resource()
82    {
83        //message( "Resource %s served by %s @ %s destroyed", name, busname, objectpath );
84    }
85
86    public bool isEnabled()
87    {
88        return ( status == ResourceStatus.ENABLED );
89    }
90
91    public bool hasUser( string user )
92    {
93        return ( user in users );
94    }
95
96    public void setPolicy( FreeSmartphone.UsageResourcePolicy policy )
97    {
98        if ( policy == this.policy )
99            return;
100
101        switch ( policy )
102        {
103            case FreeSmartphone.UsageResourcePolicy.DISABLED:
104                disable();
105                break;
106            case FreeSmartphone.UsageResourcePolicy.ENABLED:
107                enable();
108                break;
109            case FreeSmartphone.UsageResourcePolicy.AUTO:
110                if ( users.size > 0 )
111                    enable();
112                else
113                    disable();
114                break;
115            default:
116                assert_not_reached();
117
118        }
119    }
120
121    public void addUser( string user ) throws FreeSmartphone.UsageError
122    {
123        if ( user in users )
124            throw new FreeSmartphone.UsageError.USER_EXISTS( "Resource %s already requested by user %s".printf( name, user ) );
125
126        if ( policy == FreeSmartphone.UsageResourcePolicy.DISABLED )
127            throw new FreeSmartphone.UsageError.POLICY_DISABLED( "Resource %s cannot be requested by %s per policy".printf( name, user ) );
128
129        users.insert( 0, user );
130
131        if ( policy == FreeSmartphone.UsageResourcePolicy.AUTO && users.size == 1 )
132            enable();
133    }
134
135    public void delUser( string user ) throws FreeSmartphone.UsageError
136    {
137        if ( !(user in users) )
138            throw new FreeSmartphone.UsageError.USER_UNKNOWN( "Resource %s never been requested by user %s".printf( name, user ) );
139
140        users.remove( user );
141
142        if ( policy == FreeSmartphone.UsageResourcePolicy.AUTO && users.size == 0 )
143            disable();
144    }
145
146    public string[] allUsers()
147    {
148        string[] res = {};
149        foreach ( var user in users )
150            res += user;
151        return res;
152    }
153
154    public void enable() throws DBus.Error
155    {
156        try
157        {
158            proxy.enable();
159            status = ResourceStatus.ENABLED;
160        }
161        catch ( DBus.Error e )
162        {
163            instance.logger.error( "Resource %s can't be enabled %s. Trying to disable instead".printf( name, e.message ) );
164            proxy.disable();
165            throw e;
166        }
167    }
168
169    public void disable() throws DBus.Error
170    {
171        try
172        {
173            proxy.disable();
174            status = ResourceStatus.DISABLED;
175        }
176        catch ( DBus.Error e )
177        {
178            instance.logger.error( "Resource %s can't be disabled: %s. Setting status to UNKNOWN".printf( name, e.message ) );
179            status = ResourceStatus.UNKNOWN;
180        }
181    }
182
183    public void suspend() throws DBus.Error
184    {
185        if ( status == ResourceStatus.ENABLED )
186        {
187            try
188            {
189                proxy.suspend();
190                status = ResourceStatus.SUSPENDED;
191            }
192            catch ( DBus.Error e )
193            {
194                instance.logger.error( "Resource %s can't be suspended: %s. Trying to disable instead".printf( name, e.message ) );
195                proxy.disable();
196                throw e;
197            }
198        }
199        else
200        {
201            instance.logger.debug( "Resource %s not enabled: not suspending".printf( name ) );
202        }
203    }
204
205    public void resume() throws DBus.Error
206    {
207        if ( status == ResourceStatus.SUSPENDED )
208        {
209            try
210            {
211                proxy.resume();
212                status = ResourceStatus.ENABLED;
213            }
214            catch ( DBus.Error e )
215            {
216                instance.logger.error( "Resource %s can't be resumed: %s. Trying to disable instead".printf( name, e.message ) );
217                proxy.disable();
218                throw e;
219            }
220        }
221        else
222        {
223            instance.logger.debug( "Resource %s not suspended: not resuming".printf( name ) );
224        }
225    }
226}
227
228/**
229 * Controller class implementing org.freesmartphone.Usage API
230 *
231 * Note: Unfortunately we can't just use libfso-glib (FreeSmartphone.Usage interface)
232 * here, since we do some tricks with the dbus sender name,
233 **/
234[DBus (name = "org.freesmartphone.Usage")]
235public class Controller : FsoFramework.AbstractObject
236{
237    private FsoFramework.Subsystem subsystem;
238    private HashMap<string,Resource> resources;
239    private string sys_power_state;
240    private bool do_not_suspend;
241
242    dynamic DBus.Object dbus;
243
244    public Controller( FsoFramework.Subsystem subsystem )
245    {
246        this.subsystem = subsystem;
247
248        resources = new HashMap<string,Resource>( str_hash, str_equal, str_equal );
249
250        this.subsystem.registerServiceName( FsoFramework.Usage.ServiceDBusName );
251        this.subsystem.registerServiceObject( FsoFramework.Usage.ServiceDBusName,
252                                              FsoFramework.Usage.ServicePathPrefix, this );
253
254        // grab sysfs paths
255        var sysfs_root = config.stringValue( "cornucopia", "sysfs_root", "/sys" );
256        sys_power_state = Path.build_filename( sysfs_root, "power", "state" );
257        do_not_suspend = config.boolValue( CONFIG_SECTION, "do_not_suspend", false );
258
259        // start listening for name owner changes
260        dbusconn = ( (FsoFramework.DBusSubsystem)subsystem ).dbusConnection();
261        dbus = dbusconn.get_object( DBUS_BUS_NAME, DBUS_BUS_PATH, DBUS_BUS_INTERFACE );
262        dbus.NameOwnerChanged += onNameOwnerChanged;
263    }
264
265    public override string repr()
266    {
267        return "<%s>".printf( FsoFramework.Usage.ServicePathPrefix );
268    }
269
270    private void onResourceAppearing( Resource r )
271    {
272        logger.debug( "Resource %s served by %s @ %s has just been registered".printf( r.name, r.busname, r.objectpath ) );
273        this.resource_available( r.name, true ); // DBUS SIGNAL
274
275        // initial status is disabled
276        r.disable();
277    }
278
279    private void onResourceVanishing( Resource r )
280    {
281        logger.debug( "Resource %s served by %s @ %s has just been unregistered".printf( r.name, r.busname, r.objectpath ) );
282        this.resource_available( r.name, false ); // DBUS SIGNAL
283
284        // finishing status is disabled
285        r.disable();
286    }
287
288    private void onNameOwnerChanged( dynamic DBus.Object obj, string name, string oldowner, string newowner )
289    {
290        //message( "name owner changed: %s (%s => %s)", name, oldowner, newowner );
291        // we're only interested in services disappearing
292        if ( newowner != "" )
293            return;
294
295        logger.debug( "%s disappeared. checking whether resources are affected...".printf( name ) );
296
297        //FIXME: Consider keeping the known busnames in a map as well, so we don't have to iterate through all values
298        foreach ( var r in resources.get_values() )
299        {
300            // first, check whether the resource provider might have vanished
301            if ( r.busname == name )
302            {
303                onResourceVanishing( r );
304                resources.remove( r.name );
305            }
306            // second, check whether it was one of the users
307            else
308            {
309                if ( r.hasUser( name ) )
310                    r.delUser( name );
311            }
312        }
313    }
314
315    private bool onIdleForSuspend()
316    {
317        suspendAllResources();
318        logger.debug( ">>>>>>> KERNEL SUSPEND" );
319        if ( !do_not_suspend )
320            FsoFramework.FileHandling.write( "mem\n", sys_power_state );
321        else
322            Posix.sleep( 5 );
323        logger.debug( "<<<<<<< KERNEL RESUME" );
324        resumeAllResources();
325        //FIXME: enum
326        this.system_action( "suspend" ); // DBUS SIGNAL
327        return false; // MainLoop: Don't call again
328    }
329
330    private Resource getResource( string name ) throws FreeSmartphone.UsageError
331    {
332        Resource r = resources[name];
333        if ( r == null )
334            throw new FreeSmartphone.UsageError.RESOURCE_UNKNOWN( "Resource %s had never been registered".printf( name ) );
335
336        logger.debug( "current users for %s = %s".printf( r.name, FsoFramework.StringHandling.stringListToString( r.allUsers() ) ) );
337
338        return r;
339    }
340
341    private void disableAllResources()
342    {
343        foreach ( var r in resources.get_values() )
344        {
345            try
346            {
347                r.disable();
348            }
349            catch ( DBus.Error e )
350            {
351                logger.warning( "Error while trying to disable resource %s: %s".printf( r.name, e.message ) );
352            }
353        }
354    }
355
356    private void suspendAllResources()
357    {
358        foreach ( var r in resources.get_values() )
359        {
360            try
361            {
362                r.suspend();
363            }
364            catch ( DBus.Error e )
365            {
366                logger.warning( "Error while trying to suspend resource %s: %s".printf( r.name, e.message ) );
367            }
368        }
369    }
370
371    private void resumeAllResources()
372    {
373        foreach ( var r in resources.get_values() )
374        {
375            try
376            {
377                r.resume();
378            }
379            catch ( DBus.Error e )
380            {
381                logger.warning( "Error while trying to resume resource %s: %s".printf( r.name, e.message ) );
382            }
383        }
384    }
385
386    //
387    // DBUS API (for providers)
388    //
389    public void register_resource( DBus.BusName sender, string name, DBus.ObjectPath path ) throws FreeSmartphone.UsageError, DBus.Error
390    {
391        message( "register_resource called with parameters: %s %s %s", sender, name, path );
392        if ( name in resources )
393            throw new FreeSmartphone.UsageError.RESOURCE_EXISTS( "Resource %s already registered".printf( name ) );
394
395        var r = new Resource( name, sender, path );
396        resources[name] = r;
397
398        onResourceAppearing( r );
399    }
400
401    public void unregister_resource( DBus.BusName sender, string name ) throws FreeSmartphone.UsageError, DBus.Error
402    {
403        var r = getResource( name );
404
405        if ( r.busname != sender )
406            throw new FreeSmartphone.UsageError.RESOURCE_UNKNOWN( "Resource %s not yours".printf( name ) );
407
408        onResourceVanishing( r );
409
410        resources.remove( name );
411    }
412
413    //
414    // DBUS API (for consumers)
415    //
416    public FreeSmartphone.UsageResourcePolicy get_resource_policy( string name ) throws FreeSmartphone.UsageError, DBus.Error
417    {
418        return getResource( name ).policy;
419    }
420
421    public void set_resource_policy( string name, FreeSmartphone.UsageResourcePolicy policy ) throws FreeSmartphone.UsageError, DBus.Error
422    {
423        message( "set resource policy for %s to %d", name, policy );
424        getResource( name ).setPolicy( policy );
425    }
426
427    public bool get_resource_state( string name ) throws FreeSmartphone.UsageError, DBus.Error
428    {
429        return getResource( name ).isEnabled();
430    }
431
432    public string[] get_resource_users( string name ) throws FreeSmartphone.UsageError, DBus.Error
433    {
434        return getResource( name ).allUsers();
435    }
436
437    public string[] list_resources() throws DBus.Error
438    {
439        string[] res = {};
440        foreach ( var key in resources.get_keys() )
441            res += key;
442        return res;
443    }
444
445    public void request_resource( DBus.BusName sender, string name ) throws FreeSmartphone.UsageError, DBus.Error
446    {
447        getResource( name ).addUser( sender );
448    }
449
450    public void release_resource( DBus.BusName sender, string name ) throws FreeSmartphone.UsageError, DBus.Error
451    {
452        getResource( name ).delUser( sender );
453    }
454
455    public void shutdown() throws DBus.Error
456    {
457        //FIXME: enum
458        this.system_action( "shutdown" ); // DBUS SIGNAL
459        disableAllResources();
460        Posix.system( "shutdown -h now" );
461    }
462
463    public void reboot() throws DBus.Error
464    {
465        //FIXME: enum
466        this.system_action( "reboot" ); // DBUS SIGNAL
467        disableAllResources();
468        Posix.system( "reboot" );
469    }
470
471    public void suspend() throws DBus.Error
472    {
473        //FIXME: enum
474        this.system_action( "suspend" ); // DBUS SIGNAL
475        // we need to suspend async, otherwise the dbus call would timeout
476        Idle.add( onIdleForSuspend );
477    }
478
479    // DBUS SIGNALS
480    public signal void resource_available( string name, bool availability );
481    public signal void resource_changed( string name, bool state, GLib.HashTable<string,GLib.Value?> attributes );
482    public signal void system_action( string action );
483}
484
485} /* end namespace */
486
487Usage.Controller instance;
488DBus.Connection dbusconn;
489
490public static string fso_factory_function( FsoFramework.Subsystem subsystem ) throws Error
491{
492    instance = new Usage.Controller( subsystem );
493    return "fsousage.controller";
494}
495
496
497
498[ModuleInit]
499public static void fso_register_function( TypeModule module )
500{
501    debug( "usage controller fso_register_function()" );
502}
Note: See TracBrowser for help on using the repository browser.